简体   繁体   中英

Pass data between a container and its children components in react

I have a <Container /> component that takes a list of <Card /> as children:

<Container>
  <Card />
  <Card />
</Container>

<Card /> has a boolean state openExpansion that I want once changed, all sibling <Card /> would change to the same value. What is the best way to achieve that? Obviously I can have openExpansion as <Container /> state and inject it to each <Card /> . Also I don't want to use redux store as I don't know where <Container /> will be called. But is there a way to keep openExpansion as <Card /> state while achieving the same effect? Thanks!

If you want to share the same value between siblings, you should put openExpansion props in each of the child. Also if you want to change the openExpansion you can create a function in Container

class Container extends React.Component{
    ....
    state = {
        openExpansion: true
    }

    changeOpenExpansionValue = (value) => this.setState({openExpansion:value})
    render(
        <div>

        <Card openExpansion={this.state.openExpansion} 
            toggleOpenExpansion={this.changeOpenExpansionValue }/>

        <Card openExpansion={this.state.openExpansion} 
            toggleOpenExpansion={this.changeOpenExpansionValue }/>
        </div>    

    )

}

any time you want to change all the values from one child component just call this.props.toggleOpenExpansion(boolValue) from your Cards

You can't keep openExpansion value locally in each Card as it would be stored and accessible only inside of Card component and might differ from values in siblings

Just create a state in the main component and pass the function to update state to Card. Something like

   const App = () => {

   const [openExpansion, setOpenExpansion] = React.useState(false);

   return (
     <Container>
     <Card setOpenExpansion={setOpenExpansion} openExpansion={openExpansion} />
      <Card />
    <Card setOpenExpansion={setOpenExpansion} openExpansion={openExpansion} /><Card /> /* Similar to above card */
     </Container>
    );
   };

  const Card = ({setOpenExpansion openExpansion})  => {
    return (
       <div onClick={() => openExpansion(true)}>
            {openExpansion ? "opened" : ""}
       </div>
    );
  }

If I'm getting correctly this is something that you want to achieve by passing setState, state variables.

I think you explained one option which is having one variable in Container and passing it into every Card component. Another option is to use a static property inside the Card component. Every Card instance would have the same value.

It seems to me that you have to lift your state up: https://reactjs.org/docs/lifting-state-up.html

So in your case, you can create a method/function where you wrap these cards.

class WrappedCards extends React.Component {
  constructor(props) {
    super(props);
    this.handleOpenExpansion= this.handleOpenExpansion.bind(this);
    this.state = {openExpansion : false};
  }

  handleOpenExpansion(value) {
    this.setState({openExpansion : value});
  }

  render() {

    return (
      <Container>
        <Card
          handleOpenExpansion={this.handleOpenExpansion} />
      </Container>
    );
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM