Home > Blockchain >  React component function call only updates one component instance
React component function call only updates one component instance

Time:04-07

I have a component called RightTab like this

const RightTab = ({ data }) => {
  return (
    <div className="RightTab flex__container " onClick={data.onClick}>
      <img src={data.icon} alt="Dashboard Icon" />
      <p className="p__poppins">{data.name}</p>
      {data.dropDown === true ? (
        <div className="dropdown__icon">
          <img src={Assets.Arrow} alt="Arrow" />
        </div>
      ) : (
        <div className="nothing"></div>
      )}
    </div>
  );
};

export default RightTab;

The tab has an active state in its CSS like this

.RightTab.active {
  background-color: var(--primaryGreen);
}

as you have seen it changes the color when an active class is added. I have an array in the parent component that I pass down to the child component as props. Here is the array

const dataArray = [
  {
    name: "Dashboard",
    icon: Assets.Dashboard,
    dropDown: false,
    onClick: handleDashBoardClick,
  },
  {
    name: "Inventory",
    icon: Assets.Inventory,
    dropDown: true,
    onClick: handleInventoryClick,
  },
  {
    name: "Reports",
    icon: Assets.Reports,
    dropDown: true,
    onClick: handleReportsClick,
  },
];

Here is how I pass the props down.

  <RightTab data={dataArray[0]} />
  <RightTab data={dataArray[1]} />
  <RightTab data={dataArray[2]} />

The data prop passed into the component is an object containing a function call as one of its properties like this. I have an onclick attribute on the child components' main container that is supposed to call the respective function.

The function is what adds the active class to make the background change color. However each time I click on the component it only changes the background of the first occurrence. And as you may have noticed I call the component thrice. No matter which component I click only the first ones background changes.

Here is an example of the function that is on the prop object.

const handleDashBoardClick = () => {
  const element = document.querySelector(".RightTab");
  element.classList.toggle("active");
};

I don't get what I'm doing wrong. What other approach can I use?

CodePudding user response:

Although you use the component 3 times, it doesn't mean that a change you make in one of the components will be reflected in the other 2, unless you specifically use a state parameter that is passed to all 3 of them.

Also, the way you add the active class is not recommended since you mix react with pure js to handle the CSS class names.

I would recommend having a single click handler that toggles the active class for all n RightTab components:

const MainComponent = () => {
  const [classNames, setClassNames] = useState([]);
  
  const handleClick = (name) => 
  {
    const toggledActiveClass = classNames.indexOf('active') === -1
      ? classNames.concat(['active'])
      : classNames.filter((className) => className !== 'active');
      
    setClassNames(toggledActiveClass);
    
    switch (name) {
      case 'Dashboard';
        // do something
        break;
        
        case 'Inventory':
        // ....
        break;
    }
  }
  
  const dataArray = [
    {
      name: "Dashboard",
      icon: Assets.Dashboard,
      dropDown: false,
      onClick: handleClick.bind(null, 'Dashboard'),
    },
    {
      name: "Inventory",
      icon: Assets.Inventory,
      dropDown: true,
      onClick: handleClick.bind(null, 'Inventory'),
    },
    {
      name: "Reports",
      icon: Assets.Reports,
      dropDown: true,
      onClick: handleClick.bind(null, 'Reports'),
    },
  ];

  return (
    <>
      {dataArray.map((data) => 
        <RightTab key={data.name} 
                  data={data} 
                  classNames={classNames} />)}
    </>
  );
};

const RightTab = ({ data, classNames }) => {
  return (
    <div className={classNames.concat(['RightTab flex__container']).join(' ')} 
         onClick={data.onClick}>
      <img src={data.icon} alt="Dashboard Icon" />
      <p className="p__poppins">{data.name}</p>
      {data.dropDown === true ? (
        <div className="dropdown__icon">
          <img src={Assets.Arrow} alt="Arrow" />
        </div>
      ) : (
        <div className="nothing"></div>
      )}
    </div>
  );
};
  • Related