1

I am working on a React project, In my project I have two components those are App and Child. The app is Parent component and child is Child component.

Now I Changed state in Child component when I click the button on Child component.

Now my goal is how to pass latest state of the Child component for a Parent component button.

I am not getting how to do this, please help me

This is App.js

import React from 'react';
import './App.css';
import Child from './Child/Child';

function App() {
  return(
    <div className='container'>
      <div className='row'>
        <button className='btn btn-primary'>Click here</button>
        <Child></Child>
      </div>
    </div>
  )
}

export default App

This is Child.js

import React, { useState } from 'react';
import './Child.css';

function Child() {
    const [color, setColor] = useState('yellow');
    const [textColor, setTextColor] = useState('white');
    return (
        <div className='container'>
            <div className='row'>
                <button style={{ background: color, color: textColor }} 
                onClick={()=>{setColor("black");setTextColor('red')}}className='btn btn-danger mt-5'>Click here</button>
            </div>
        </div>
    )
}

export default Child

If you feel that I am not clear with my doubt, please put a comment. Thank you.

Cruse
  • 595
  • 1
  • 12
  • 22

3 Answers3

1

You can not pass data from children to parent, just store data in parent and pass it to children like below

function App() {

const [color, setColor] = useState('yellow');
  const [textColor, setTextColor] = useState('white');
  return (
    <div className='container'>
      <div className='row'>
        <button className='btn btn-primary'>Click here</button>
        <Child
           color={color} 
           setColor={color => setColor(color)}
           textColor={textColor}
           setTextColor={textColor => setTextColor(textColor)}
        />
      </div>
    </div>
  )
}

export default App

import React from 'react';
import './Child.css';

function Child(props) {
    const {color, setColor, textColor, setTextColor} = props;
    return (
        <div className='container'>
            <div className='row'>
                <button style={{ background: color, color: textColor }} 
                onClick={()=>{setColor('red');setTextColor('black')}}className='btn btn-danger mt-5'>Click here</button>
            </div>
        </div>
    )
}

export default Child
iamhuynq
  • 5,357
  • 1
  • 13
  • 36
  • Hi @iamhuynq it is showing error like this: Expected an assignment or function call and instead saw an expression no-unused-expressions : Expected an assignment or function call and instead saw an expression no-unused-expressions – Cruse Mar 19 '20 at 13:48
  • You need to call the setters: `onClick={()=>{setColor(withWhat?);setTextColor(withWhat?)}}` – HMR Mar 19 '20 at 13:48
  • Hi @Cruse this error maybe because of bracket of `return`, you can check here https://stackoverflow.com/questions/53013437/expected-assignment-or-function-call-no-unused-expressions-reactjs @HMR thank you, I have updated the code – iamhuynq Mar 19 '20 at 14:00
0

define a function in parent component to

  1. receive an argument i.e., child state here as per you question
  2. pass this function as a prop to the child component
  3. call this function from child component before or after setting the its state, as needed in your context.

I have used this method many a times while building react apps. Please accept this as answer if it helps you out.

keikai
  • 14,085
  • 9
  • 49
  • 68
user2063635
  • 214
  • 1
  • 10
0

If your Child component has complex logic that you don't want the Parent to be bothered with you can pass a callback from Parent to the Child:

function Child({ onColorChanged }) {
  //The disadvantage of this is that you can't pass in
  //  default values for color and textColor from Parent
  const [color, setColor] = React.useState('yellow');
  const [textColor, setTextColor] = React.useState('white');
  //When color or textColor changes call the onColorChanged
  //  callback/event handler
  React.useEffect(
    () => onColorChanged({ color, textColor }),
    //the onColorChanged callback/event handler is
    //  a dependency of this effect, that is why
    //  Parent uses useCallback so it won't change
    //  when parent re renders
    [color, textColor, onColorChanged]
  );
  return (
    <div className="container">
      <div className="row">
        <button
          style={{ background: color, color: textColor }}
          onClick={() => {
            //some complicated logic you don't want in the
            //  parent
            setColor('black');
            setTextColor('red');
          }}
          className="btn btn-danger mt-5"
        >
          Click here
        </button>
      </div>
    </div>
  );
}

function Parent() {
  const [state, setState] = React.useState();
  const onColorChanged = React.useCallback(
    color => setState(old => ({ ...old, color })),
    []
  );
  console.log('state is now:', state);
  return (
    <div className="container">
      <div className="row">
        <button className="btn btn-primary">
          Click here
        </button>
        <Child onColorChanged={onColorChanged}></Child>
      </div>
    </div>
  );
}

ReactDOM.render(<Parent />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

If Child does not have complicated logic that you don't want in Parent you can just have Parent manage the state and pass a callback when something changes.

const colors = ['yellow', 'gold', 'black', 'white'];
function Child({ setColor, color: { color, textColor } }) {
  return (
    <div className="container">
      <h1 style={{ background: color, color: textColor }}>
        Hello world
      </h1>
      <label>
        color
        <select
          value={color}
          onChange={e => setColor('color', e.target.value)}
        >
          {colors.map(c => (
            <option value={c} key={c}>
              {c}
            </option>
          ))}
        </select>
      </label>
      <label>
        text color
        <select
          value={textColor}
          onChange={e =>
            setColor('textColor', e.target.value)
          }
        >
          {colors.map(c => (
            <option value={c} key={c}>
              {c}
            </option>
          ))}
        </select>
      </label>
    </div>
  );
}

function App() {
  const [state, setState] = React.useState({
    color: 'yellow',
    textColor: 'white',
  });
  const setColor = React.useCallback(
    (key, value) =>
      setState(old => ({ ...old, [key]: value })),
    []
  );
  return (
    <div className="container">
      <div className="row">
        <Child setColor={setColor} color={state}></Child>
      </div>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
HMR
  • 37,593
  • 24
  • 91
  • 160