react-component / react-component/tabs

Fix: Tab click events firing multiple times due to missing useCallback dependency

Open Beginner friendly
#865 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
572
Forks
241
Avg merge
4d 18h
Merged PRs (30d)
4

Description

Problem Description

When using rc-tabs, tab click events can fire multiple times unexpectedly, especially when the component re-renders frequently. This happens because the onInternalTabClick function is recreated on every render without proper memoization.

Root Cause

The issue is in the Tabs.js file where onInternalTabClick function is defined as a regular function instead of using React.useCallback. This causes the function to be recreated on every render, which can lead to:

  1. Unnecessary re-renders of child components
  2. Multiple event handlers being attached
  3. Click events firing multiple times

Solution

The fix involves two main changes:

  1. Memoize tab keys: Use React.useMemo to memoize the tab keys array to prevent unnecessary re-computations
  2. Memoize click handler: Wrap onInternalTabClick with React.useCallback to prevent function recreation on every render
Code Changes
// Before
var tabKeys = React.useMemo(function () {
  return tabs.map(function (tab) {
    return tab.key;
  });
}, [tabs]);

// After
var tabKeys = React.useMemo(function () {
  return tabs.map(function (tab) {
    return tab.key;
  });
}, [tabs]);

// Before
function onInternalTabClick(key, e) {
  onTabClick === null || onTabClick === void 0 || onTabClick(key, e);
  var isActiveChanged = key !== mergedActiveKey;
  setMergedActiveKey(key);
  if (isActiveChanged) {
    onChange === null || onChange === void 0 || onChange(key);
  }
}

// After
var onInternalTabClick = React.useCallback(function (key, e) {
  onTabClick === null || onTabClick === void 0 || onTabClick(key, e);
  var isActiveChanged = key !== mergedActiveKey;
  setMergedActiveKey(key);
  if (isActiveChanged) {
    onChange === null || onChange === void 0 || onChange(key);
  }
}, [onTabClick, mergedActiveKey, onChange]);

Reproduction Steps

  1. Create a Tabs component with dynamic content
  2. Add console.log in the onChange handler
  3. Click on a tab multiple times
  4. Observe that the onChange handler fires multiple times for a single click

Expected Behavior

Each tab click should trigger the onChange handler exactly once, regardless of component re-renders.

Environment

  • rc-tabs version: [affected versions]
  • React version: [tested versions]
  • Browser: All browsers

Impact

This issue affects applications that:

  • Have frequent re-renders
  • Use dynamic tab content
  • Rely on accurate click event handling
  • Need to prevent duplicate API calls or state updates

The fix improves performance and prevents unexpected behavior in applications using rc-tabs.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by inspecting Tabs.js, focusing on the onInternalTabClick function and the tabKeys memoization described in the issue. Reproduce the behavior with dynamically changing tab content and frequent re-renders, then verify that each tab click invokes onChange exactly once.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.