简体   繁体   中英

Pass data to one of the same components

<Comp1 />
<div>
    <Comp1 />
    <Comp2 />
</div>

I am new to React. I want to pass data from Comp2 to its sibling Comp1 only. I know using a parent component to pass props but in this case I have to rewrite Comp1 to get state from its parent, which will affect all the Comp1. How can I make only chosen Comp1 receive the data and don't bother the else?

There is not a straightforward solution to this, but you do have a couple of options:

Option 1

The most direct way would be as you described - having Comp2 pass data up to its parent using an event listener, then having the parent pass it back down to Comp1. This can be an optional prop being passed to Comp1, so it doesn't matter that your outer Comp1 won't receive that prop.

For example:

import React from 'react';

const Comp1 = ({data='Default Value'}) => (
  <p>{data}</p>
)

const Comp2 = ({onData}) => (
  <button onClick={e => onData(Math.random())}>Change Value</button>
)


export default function App() {
  let [data, setData] = React.useState(null);
  return (
    <div>
      <Comp1/>
      <div>
        <Comp1 data={data}/>
        <Comp2 onData={setData}/>
      </div>
    </div>
  );
}

This is probably your best option, and by the sound of things, it might be good to find a way to refactor your app so that this option becomes more viable. There's usually a way to change your app structure to make this work better.

If you really want siblings to have a more direct line of communication with each other, you could give Comp1 a ref of Comp2, but I wouldn't encourage this.

Option 2

Another option would be to use contexts . This gives anyone the power to communicate with anyone who uses the same context. There is a lot of power in this feature. Some people set up a Redux-like system using contexts and reducers to let any part of the application (or larger component they put the context provider in) communicate with any other part. See this article for more information on using contexts to manage application state.

import React from 'react';

let context = React.createContext()

const Comp1 = () => {
  let ctx = React.useContext(context) || {};
  return <p>{ctx.data || 'Default Value'}</p>
}

const Comp2 = () => {
  let ctx = React.useContext(context);
  return <button onClick={e => ctx.setData(Math.random())}>Change Value</button>
}

export default function App() {
  let [data, setData] = React.useState();
  return (
    <div>
      <Comp1/>
      <div>
        <context.Provider value={{data, setData}}>
          <Comp1/>
          <Comp2/>
        </context.Provider>
      </div>
    </div>
  );
}

Option 3

For completeness, A third option would be using something like Redux to help share state. Only use this option if you are already using Redux, or if you really want/need it and understand what you're getting into. Redux is not for every project, everyone does not need it.

Side Note

I realize you said you were new to React. For brevity and for other Googlers, I used a lot of React hooks in my examples (The functions like React.useState, React.useContext, etc). These can take a little bit to understand, and I don't expect you to learn how to use them just to solve your problem. In fact, if you're new to React, I would strongly encourage you to just go with option 1 using the class syntax you've learned how to use already. As you get some more practice and start feeling the limits of the first option, then you can start trying the other things out.

In react, data always moves from top to down, so there is no true way to pass information sibling to sibling without going through some higher structure. You could use context, but again, its provider has to wrap around both sibling components, meaning it has to be implemented in the parent component(App). It is also intended for passing data between deeply nested sibling components to avoid passing props multiple levels deep. In your case where props only have to be passed one level deep, it is best to just store state in the parent component(App).

Here is what context would look like for your App (its more trouble than its worth at this point): https://codesandbox.io/s/objective-hellman-sdm55?file=/src/App.js

For this use case I would suggest using the useState hook in the parent component and passing down a value & function to the specific child components.

pseudo code:

<Parent>
    const [value, setValue] = useState();
    <Comp1 onClick={setvalue} />
    <Comp2 value={value} />
</Parent>

In my opinion, for your use case, Redux and the Context API are a bit overkill.

You can research about state and props. References: https://flaviocopes.com/react-state-vs-props

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