Pass props with callback from Parent to component

Tags: ,



I have this parent App.jsx, with two components <Child1/> and <Child2/> imported.

export default function App() {
  const [isFlipped, setIsFlipped] = React.useState(false);
  
  const handleSelectPlayers = () => {
    setIsFlipped(true);
  }

  const handleDeselectPlayers = () => {
    setIsFlipped(false);
  }

  return (
    <Flippy
      isFlipped={isFlipped}
      flipDirection="horizontal" // horizontal or vertical
      style={{ width: "400px", height: "600px" }} /// these are optional style, it is not necessary
    >
      <FrontSide>
        <Child1 onSelectPlayers={handleSelectPlayers} /> // <-----
      </FrontSide>
      <BackSide>
        <Child2 onDeselectPlayers={handleDeselectPlayers} /> // <-----
      </BackSide>
    </Flippy>
  );
}

This is Child1.jsx, where I have ‘players’ set locally by this.setState():

class Child1 extends Component {
  constructor(props) {
    super(props);

    this.state = {
      players:[]
    };
  }

  async getPlayers() {
      const res = await fetch("/json/players.json");
      const data = await res.json();
      const players = Object.values(data.Players)

        this.setState({ 
          players: players
        },() => console.log(this.state.players));
      }

    handlePlayers = () => {
        this.props.onSelectPlayers();
      };

    render() {
        return (
        ...
        <Button handleClick={() => this.handlePlayers()}></Button>
        ...
        );

And here Child2.jsx, which needs ‘players’ as props, given the fact they are fetched at Child1.jsx.

class Child2 extends Component {
  constructor(props) {
    super(props);

    this.state = {
      players:[]
    };
  }


 handlePlayers = () => {
    // do something with players here
  };

handleChangePlayers = () => {
    this.props.onDeselectPlayers();
  };

  render() {
    return (
      ...
      <Button handleClick={() => this.handlePlayers()}> 
      <Button handleClick={() => this.handleChangePlayers()}>
      ... 
    );
  }

I know I can achieve this by having a callback to App.jsx at Child1.jsx, so I can pass players as props to Child2.jsx, but how so?

Answer

You can keep the players state on the Parent of both Child components. This way, you can pass it down as props to the relevant components. Refer to my comments on the code for insight

function App(){
  const [players, setPlayers] = React.useState(); // single source of truth for players
  
  return (
    <React.Fragment>
      <Child1 setPlayers={setPlayers}/> // pass state setter to Child1 where you perform the xhr to fetch players
      <Child2 players={players}/> // pass players down as props to Child2
    </React.Fragment>
  )
}

class Child1 extends React.Component{

  componentDidMount(){
    this.getPlayers(); // sample fetching of players
  }

  getPlayers() {
    this.props.setPlayers([ // set players state which resides on the parent component "App"
      "foo",
      "bar"
    ]);
  }
  
  render() {return "Child1"}
}

class Child2 extends React.Component{

  componentDidUpdate(){
    // this.props.players contains updated players
    console.log(`Child2 players`, this.props.players);  
  }

  render() {return "Child2"}
}

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

<div id="root"></div>


Source: stackoverflow