admin管理员组文章数量:1022705
Here's my current model, check it out, plz
import ponent 1 & 2
export default class App extends Component {
render() {
return (
<Component1/>
<Component2/>
);
}
}
Inside ponent 1, I have a function: pushData() after running this function, I want to execute next with fetchData() on ponent 2 but I can't find out way to reference to 2 from 1 because they're not parent-child?!
Here's my current model, check it out, plz
import ponent 1 & 2
export default class App extends Component {
render() {
return (
<Component1/>
<Component2/>
);
}
}
Inside ponent 1, I have a function: pushData() after running this function, I want to execute next with fetchData() on ponent 2 but I can't find out way to reference to 2 from 1 because they're not parent-child?!
Share Improve this question edited May 16, 2020 at 4:44 Shubham Khatri 283k58 gold badges431 silver badges411 bronze badges asked May 16, 2020 at 4:29 user3536460user3536460 752 silver badges10 bronze badges 1- you can use the propriety boolean, when you will finish your fist operation, use setStatus react function to update the ponent tree and your second ponent can run the second function – vincenzopalazzo Commented May 16, 2020 at 4:49
5 Answers
Reset to default 2This can be done in a lot of ways, considering the code shared above has Class based implementation, I would suggest the following solution.
- First pass a function to the Component1, name it dataPushed.
- Second, create a state variable in the parent, name it dataPushed, initialize it to be false.
- Third pass a function and a state variable from parent to Component2, name it dataFetched and fetchData respectively.
Now Component1 will have it's own function to push the data, let's call this function pushData. As soon as the logic for pushing data is over, call the passed prop function dataPushed. This props will update the parent state with current status i.e. data is pushed and set the state variable to be true.
Now this state variable is passed to the Component2 already, using ComponentDidUpdate in Component 2. We can know the state of dataPush from ponent 1 and if it is true, you can call the Component2 internal function to fetch the data.
As soon as the data is fetched, call the prop passed to this Component2 to let the parent know that latest data has been fetched and set the parent state variable for dataPushed to be false.
Ignore the function and variable names used, feel free to use yours.
I have created a Sandbox with code,
https://codesandbox.io/s/affectionate-forest-5kc68?file=/src/App.js
I hope this solves your problem. Let me know if you are still stuck or unclear about any of the above explanation.
Architecturally what you're trying to do is not a good idea.
For example, if you change the ponent that has the function you want to use, you'll need to remember to update any dependencies that use this function. This bees hard to maintain.
React props actually make it really easy to solve this problem using the dependency injection pattern. If you're not familiar with dependency injection, it essentially means that the dependencies e from the top down, the ponent that needs these dependencies doesn't know where this dependency is and isn't going out to get them. It simply gets the dependency passed in.
Instead of trying to use the method that lives in the sibling ponent, you can bring the function one level up and have it live in a parent ponent. Same with the state.
Imagine this parent:
class Container extends React.Component {
state = {
counter: 0
};
reallyCoolFunction = () => {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<>
<Cool
counter={this.state.counter}
doCoolThing={this.reallyCoolFunction}
/>
<Wannabe doCoolThing={this.reallyCoolFunction} />
</>
);
}
}
The above Container
ponent creates the function and passes it to both ponents. Each ponent would then call the function when needed, for example:
class Wannabe extends React.Component {
handleClick = () => {
this.props.doCoolThing();
};
render() {
return (
<div>
<h2>Wannabe</h2>
<button onClick={this.handleClick}>click</button>
</div>
);
}
}
Then the ponent that in your app owns the function gets the relevant props passed down:
class Cool extends React.Component {
handleClick = () => {
this.props.doCoolThing();
};
render() {
return (
<div>
<h2>Cool</h2>
<p>{this.props.counter}</p>
<button onClick={this.handleClick}>click</button>
</div>
);
}
}
If your app is growing and you're planning on working on it for a while, you may want to consider implementing a state management solution like Redux. It makes state management easier.
If you were to use functional ponents instead of class ponents, a third option is available to you, and that's building your own custom hooks. If you're not yet familiar with hooks, that might be a bit of a learning curve. You can read the React hooks documentation on how to do that.
I have created a demo of the container ponent and child ponent example described. In this example they both have the ability to update state that is displayed in the Cool
ponent: https://codesandbox.io/s/dry-hill-r425r?file=/src/App.js
You've got to pass a callback from the parent which will be called after your first function is executed, update parent's state and then pass a prop to the second ponent in order to inform it.
import React from "react";
class Component1 extends React.Component {
ponentDidMount() {
// execute your first function here
if (this.props.onPushData) {
this.props.onPushData();
}
}
render() {
return <p>Component1</p>;
}
}
class Component2 extends React.Component {
ponentDidUpdate(prevProps) {
if (prevProps.dataPushed !== this.props.dataPushed) {
if (this.props.dataPushed) {
// execute your second function here
}
}
}
render() {
return <p>Component2</p>;
}
}
export default class extends React.Component {
state = {
dataPushed: false
}
handleDataPush = () => {
this.setState({ dataPushed: true })
}
render() {
return (
<div>
<Component1 onPushData={this.handleDataPush} />
<Component2 dataPushed={this.state.dataPushed} />
</div>
);
}
}
Here's an example
One way to access ponent2's function in ponent1 is to use refs
.
Working demo is here.
Code Snippet:
export default class App extends React.Component {
ref = React.createRef();
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Component1 p2Ref={this.ref} />
<Component2 ref={this.ref} />
</div>
);
}
}
// Component1.js
export default class Component1 extends React.Component {
pushData = () => {
// make the first api call..
console.log("p 1 fun");
// now call ponent2 function
console.log(this.props);
this.props.p2Ref.current.fetchData();
};
render() {
return (
<div className="App">
<h1>ponent 1</h1>
<button onClick={this.pushData}>push data button</button>.
</div>
);
}
}
// Component2.js
export default class Component2 extends React.Component {
fetchData = () => {
console.log("p 2 fun");
};
render() {
return (
<div className="App">
<h1>ponent 2</h1>
</div>
);
}
}
Best way is to handle your scenario is to lift the fetchData
function up to the parent and pass it as prop to the ponent2
.
Like this
export default class App extends React.Component {
state = {
data: []
};
fetchData = () => {
// fetch the data and update the state(data) and pass it as prosp in ponent 2
console.log("p 2 fun");
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Component1 fetchData={this.fetchData} />
<Component2 data={this.state.data} fetchData={this.fetchData} />
</div>
);
}
}
// Component 1 pushData function
...
pushData = () => {
// make the first api call..
console.log("p 1 fun");
// now call ponent2 function
console.log(this.props);
this.props.fetchData();
};
...
In the long term, I would remend you to add Redux to the current stack, react has a limitation to scale with big hierarchy ponents and integration with backend API.
So if you are looking for a real project in the production, it is time to switch to React-Redux
Here's my current model, check it out, plz
import ponent 1 & 2
export default class App extends Component {
render() {
return (
<Component1/>
<Component2/>
);
}
}
Inside ponent 1, I have a function: pushData() after running this function, I want to execute next with fetchData() on ponent 2 but I can't find out way to reference to 2 from 1 because they're not parent-child?!
Here's my current model, check it out, plz
import ponent 1 & 2
export default class App extends Component {
render() {
return (
<Component1/>
<Component2/>
);
}
}
Inside ponent 1, I have a function: pushData() after running this function, I want to execute next with fetchData() on ponent 2 but I can't find out way to reference to 2 from 1 because they're not parent-child?!
Share Improve this question edited May 16, 2020 at 4:44 Shubham Khatri 283k58 gold badges431 silver badges411 bronze badges asked May 16, 2020 at 4:29 user3536460user3536460 752 silver badges10 bronze badges 1- you can use the propriety boolean, when you will finish your fist operation, use setStatus react function to update the ponent tree and your second ponent can run the second function – vincenzopalazzo Commented May 16, 2020 at 4:49
5 Answers
Reset to default 2This can be done in a lot of ways, considering the code shared above has Class based implementation, I would suggest the following solution.
- First pass a function to the Component1, name it dataPushed.
- Second, create a state variable in the parent, name it dataPushed, initialize it to be false.
- Third pass a function and a state variable from parent to Component2, name it dataFetched and fetchData respectively.
Now Component1 will have it's own function to push the data, let's call this function pushData. As soon as the logic for pushing data is over, call the passed prop function dataPushed. This props will update the parent state with current status i.e. data is pushed and set the state variable to be true.
Now this state variable is passed to the Component2 already, using ComponentDidUpdate in Component 2. We can know the state of dataPush from ponent 1 and if it is true, you can call the Component2 internal function to fetch the data.
As soon as the data is fetched, call the prop passed to this Component2 to let the parent know that latest data has been fetched and set the parent state variable for dataPushed to be false.
Ignore the function and variable names used, feel free to use yours.
I have created a Sandbox with code,
https://codesandbox.io/s/affectionate-forest-5kc68?file=/src/App.js
I hope this solves your problem. Let me know if you are still stuck or unclear about any of the above explanation.
Architecturally what you're trying to do is not a good idea.
For example, if you change the ponent that has the function you want to use, you'll need to remember to update any dependencies that use this function. This bees hard to maintain.
React props actually make it really easy to solve this problem using the dependency injection pattern. If you're not familiar with dependency injection, it essentially means that the dependencies e from the top down, the ponent that needs these dependencies doesn't know where this dependency is and isn't going out to get them. It simply gets the dependency passed in.
Instead of trying to use the method that lives in the sibling ponent, you can bring the function one level up and have it live in a parent ponent. Same with the state.
Imagine this parent:
class Container extends React.Component {
state = {
counter: 0
};
reallyCoolFunction = () => {
this.setState({ counter: this.state.counter + 1 });
};
render() {
return (
<>
<Cool
counter={this.state.counter}
doCoolThing={this.reallyCoolFunction}
/>
<Wannabe doCoolThing={this.reallyCoolFunction} />
</>
);
}
}
The above Container
ponent creates the function and passes it to both ponents. Each ponent would then call the function when needed, for example:
class Wannabe extends React.Component {
handleClick = () => {
this.props.doCoolThing();
};
render() {
return (
<div>
<h2>Wannabe</h2>
<button onClick={this.handleClick}>click</button>
</div>
);
}
}
Then the ponent that in your app owns the function gets the relevant props passed down:
class Cool extends React.Component {
handleClick = () => {
this.props.doCoolThing();
};
render() {
return (
<div>
<h2>Cool</h2>
<p>{this.props.counter}</p>
<button onClick={this.handleClick}>click</button>
</div>
);
}
}
If your app is growing and you're planning on working on it for a while, you may want to consider implementing a state management solution like Redux. It makes state management easier.
If you were to use functional ponents instead of class ponents, a third option is available to you, and that's building your own custom hooks. If you're not yet familiar with hooks, that might be a bit of a learning curve. You can read the React hooks documentation on how to do that.
I have created a demo of the container ponent and child ponent example described. In this example they both have the ability to update state that is displayed in the Cool
ponent: https://codesandbox.io/s/dry-hill-r425r?file=/src/App.js
You've got to pass a callback from the parent which will be called after your first function is executed, update parent's state and then pass a prop to the second ponent in order to inform it.
import React from "react";
class Component1 extends React.Component {
ponentDidMount() {
// execute your first function here
if (this.props.onPushData) {
this.props.onPushData();
}
}
render() {
return <p>Component1</p>;
}
}
class Component2 extends React.Component {
ponentDidUpdate(prevProps) {
if (prevProps.dataPushed !== this.props.dataPushed) {
if (this.props.dataPushed) {
// execute your second function here
}
}
}
render() {
return <p>Component2</p>;
}
}
export default class extends React.Component {
state = {
dataPushed: false
}
handleDataPush = () => {
this.setState({ dataPushed: true })
}
render() {
return (
<div>
<Component1 onPushData={this.handleDataPush} />
<Component2 dataPushed={this.state.dataPushed} />
</div>
);
}
}
Here's an example
One way to access ponent2's function in ponent1 is to use refs
.
Working demo is here.
Code Snippet:
export default class App extends React.Component {
ref = React.createRef();
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Component1 p2Ref={this.ref} />
<Component2 ref={this.ref} />
</div>
);
}
}
// Component1.js
export default class Component1 extends React.Component {
pushData = () => {
// make the first api call..
console.log("p 1 fun");
// now call ponent2 function
console.log(this.props);
this.props.p2Ref.current.fetchData();
};
render() {
return (
<div className="App">
<h1>ponent 1</h1>
<button onClick={this.pushData}>push data button</button>.
</div>
);
}
}
// Component2.js
export default class Component2 extends React.Component {
fetchData = () => {
console.log("p 2 fun");
};
render() {
return (
<div className="App">
<h1>ponent 2</h1>
</div>
);
}
}
Best way is to handle your scenario is to lift the fetchData
function up to the parent and pass it as prop to the ponent2
.
Like this
export default class App extends React.Component {
state = {
data: []
};
fetchData = () => {
// fetch the data and update the state(data) and pass it as prosp in ponent 2
console.log("p 2 fun");
};
render() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Component1 fetchData={this.fetchData} />
<Component2 data={this.state.data} fetchData={this.fetchData} />
</div>
);
}
}
// Component 1 pushData function
...
pushData = () => {
// make the first api call..
console.log("p 1 fun");
// now call ponent2 function
console.log(this.props);
this.props.fetchData();
};
...
In the long term, I would remend you to add Redux to the current stack, react has a limitation to scale with big hierarchy ponents and integration with backend API.
So if you are looking for a real project in the production, it is time to switch to React-Redux
本文标签: javascriptReactCall function from 39sibling39 componentStack Overflow
版权声明:本文标题:javascript - React - Call function from 'sibling' component - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745572077a2156793.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论