Передача реквизитов с обратным вызовом от родительского компонента

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть этот родительский элемент App.jsx с двумя компонентами <Child1/> и <Child2/> импортированный.

 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>
  );
}
  

Это Child1.jsx , где у меня есть «игроки», установленные локально с помощью 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>
        ...
        );
  

И здесь Child2.jsx , которому нужны «игроки» как props , учитывая тот факт, что они извлекаются 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()}>
      ... 
    );
  }
  

Я знаю, что могу добиться этого, выполнив обратный вызов App.jsx at Child1.jsx , чтобы я мог передавать игроков в качестве реквизита Child2.jsx , но как это сделать?

Комментарии:

1. reactjs.org/docs/context.html

2. являются ли Child1 amp; Child2 братьями и сестрами? и у них есть общий родитель App ?

3. Я не знаю, что вы подразумеваете под «братьями и сестрами», извините… Я использую терминологию, чтобы показать иерархию

4. Я имею в виду, является ли ваша структура чем-то вроде этого <Parent><Child1/><Child2/></Parent> ?

5. да, я так думаю…

Ответ №1:

Вы можете сохранить players состояние родительского компонента обоих дочерних компонентов. Таким образом, вы можете передать его в качестве реквизита соответствующим компонентам. Обратитесь к моим комментариям к коду для понимания

 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>