skip to Main Content

I have a parent component which is created through using another component by iterating over a for loop n number of times, and an id is assigned to each child.

Now, I need to change the state of each child from within the parent. But each individual piece has to be changed one at a time, depending on the input.

How can I achieve this? Do I have to declare n number of state variables?

const Parent = () => {
  const [color1, setColor1] = useState('yellow')
  const [color2, setColor2] = useState('yellow')

  function updateState1 () {
    setColor1('red')
  }

  function updateState2 () {
    setColor2('red')
  }

  return (
    <>
      <div>Parent</div>
      <Child childState={color1} updateState={updateState1} id='1' />
      <Child childState={color2} updateState={updateState2} id='2' />
    </>
  )
}

Below is the child component. I understand that the id is not doing anything here.
I want to be able to just have one function through which I can pass the id of the button I want to target
and the color i want to set it to.

const btnStyle = {
  backgroundColor: 'green'
}

const Child = ({ childState, updateState, id, targetButton }) => {
  
  function handleClick () {
    updateState()
  }
  
  return (
    <button id={id} style={((childState === null) && a==id) ? btnStyle: {"backgroundColor":childState}} onClick={handleClick}>
      Click me
    </button>
  )
}

2

Answers


  1. You can use an array or an object to store the state values for each child component and pass a function from the parent component to the child component that can update the state value based on the id or index of the child component.

    For example:

    import { useState } from "react";
    
    const Child = ({ color, updateColor }) => {
      function handleClick() {
        updateColor("red");
      }
    
      return (
        <button style={{ backgroundColor: color }} onClick={handleClick}>
          Click me
        </button>
      );
    };
    
    export default function Parent() {
      const [colors, setColors] = useState(["yellow", "yellow"]);
    
      function updateColor(index, color) {
        const newColors = [...colors];
        newColors[index] = color;
        setColors(newColors);
      }
    
      return (
        <>
          <div>Parent</div>
          <Child color={colors[0]} updateColor={(color) => updateColor(0, color)} />
          <Child color={colors[1]} updateColor={(color) => updateColor(1, color)} />
        </>
      );
    }
    

    You can see the result of this example here: codesandbox.io

    Login or Signup to reply.
  2. Make the child as simple as possible, and control the state and the state change in the parent:

    const { useState, Fragment } = React
    
    const defaultColor = 'yellow';
    
    const Child = ({ color, handleClick }) => (
      <button style={{ backgroundColor: color }} onClick={handleClick}>
        Click me
      </button>
    )
    
    const Parent = () => {
      const [colors, setColors] = useState({})
    
      function setColor(id) {
        setColors(prev => {     
          return { 
            ...prev, 
            [id]: !prev[id] || prev[id] === defaultColor 
              ? 'red'
              : defaultColor
          }
        })
      }
    
      return (
        <Fragment>
          <div>Parent</div>
          {Array.from({ length: 4 }, (_, id) => (
            <Child 
              key={id}
              color={colors[id] || defaultColor} 
              handleClick={() => setColor(id)} />
          ))}
        </Fragment>
      )
    }
    
    ReactDOM
      .createRoot(root)
      .render(<Parent />)
    <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
    
    <div id="root"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search