Home > database >  React how to add class to parent element when child element is clicked
React how to add class to parent element when child element is clicked

Time:11-03

This is my code.

export default MainContent = () => {
    handleClick = (e) => {
        // This is where I got confused
    };

    return (
        <>
            <div>
                <div onClick={handleClick}>1</div>
            </div>
            <div>
                <div onClick={handleClick}>2</div>
            </div>
            <div>
                <div onClick={handleClick}>3</div>
            </div>
        </>
    );
}

What I want is to add a class to parent div when child element is clicked. I couldn't use useState() since I only need one element to update. Couldn't use setAttribute since it changes the same element. Is there any solution for that?

CodePudding user response:

I take it you want to apply the class only to direct parent of clicked child.

  • create a state to oversee different clicked child div
  • apply the class only to direct parent of clicked* child div based on the state
  • make use of clsx npm package (since we don't wanna overwrite parent div styling)
  • you may see the working examples here: https://codesandbox.io/s/happy-babbage-3eczt
import { useState } from "react";
import "./styles.css";
import styled from "styled-components";
import classnames from "clsx";

export default function App() {
  const [styling, setstyling] = useState({
    status: false,
    from: "",
    style: ""
  });

  function handleClick(childNo) {
    setstyling({ status: true, from: childNo, style: "applyBgColor" });
  }

  return (
    <div className="App">
      <Styling>
        <div
          className={
            styling?.status && styling?.from == "child-1"
              ? classnames("indentText", styling?.style)
              : "indentText"
          }
        >
          <div
            className="whenHoverPointer"
            onClick={() => handleClick(`child-1`)}
          >1</div>
        </div>
        <div
          className={
            styling?.status && styling?.from == "child-2" 
              ? styling?.style 
              : ""
          }
        >
          <div
            className="whenHoverPointer"
            onClick={() => handleClick(`child-2`)}
          >2</div>
        </div>
      </Styling>
    </div>
  );
}

const Styling = styled.div`
  .indentText {
    font-style: italic;
  }
  .applyBgColor {
    background-color: grey;
  }
  .whenHoverPointer {
    cursor: pointer;
  }
`;

CodePudding user response:

function Item({ children }) {
  const [checked, isChecked] = useState(false);
  const onClick = () => isChecked(true);

  return (
    <div {...(isChecked && { className: 'foo' })}>
      <button type="button" onClick={onClick}>{children}</button>
    </div>
  );
}

function MainContent() {
  return [1, 2, 3].map(n => <Item key={n}>{n}</Item>);
}

CodePudding user response:

I think theirs something wrong, useState and JSX will update related part, react will handling that itself, but base on logic, may you need to prevent re-render to stop issue, for example, here on handleClick, will keep re-render in each state since function will re-addressed in memory each update..

any way, base on your question, you can do that by this:

  const handleClick = useCallback((e) => {
    e.target.parentElement.classList.add('yourClass')
  }, []);

But I believe its a Bad solution.

What I recommend is solve issue by state to keep your react life cycle is fully work and listen to any update, also you can use ref to your wrapper div and add class by ref.

  • Related