Reputation: 13275
I've created two components in React, <Search />
and <List />
that both are children of <App />
.
When a button in <Search />
is clicked, I want to fetch something from an API and display the results in <List />
. While I got this working by doing the fetch inside <App />
and passing the response as prop to <List />
, I would prefer to encapsulate the fetch inside <List />
.
Unfortunately I am having a hard time finding a way to do this. 'The React way' probably would be to do this via some clever prop passing, but I haven't found a neat way to do this – even a 'shouldFetch' boolean would need to be reset after the fetch which seems cumbersome and would trigger unnecessary renders.
This answer uses refs
for something similar which might work, but actually I am a bit hesitant to try it since refs
seem to be a bit dirty, according to the React docs, as they "imperatively modify a child outside of the typical dataflow".
How can I instruct my <List />
component to do something after a button in <Search />
has been clicked?
If required I can supply code – but hoping this question is simpler than it seems to me.
Upvotes: 5
Views: 4128
Reputation: 562
This will be a good time to use a store, which will keep the entire state of your app as a single JS object. Flux, Redux are 2 excellent architectures which complement React. Basically, your components listen for changes in the store, when ever any action ( making an api call / click etc ) is carried out the store gets updated and the ui changes. A large scale react application can get very messy to handle with lots of children.
Also completely agree with the above answer, let the <List />
component be stateless, and only render based on props. Hence having the functions written in the parent <App/>
and have the data passed down is a good idea.
Upvotes: 0
Reputation: 1432
A natural option would be to create a state boolean variable in <App />
, triggered when a button is pressed in <Search />
and then use some logic in <List />
to fetch data when the boolean state went from false
to true
.
For example:
class App extends React.Component {
constructor() {
super();
this.state = { fetchData: false }
}
render() {
return (
<div>
<Search onClick={() => this.setState({fetchData: true})} />
<List shouldFetch={this.state.fetchData} onFetch={() => this.setState({fetchData: false})} />
</div>
)
}
}
Then in your <List />
component:
class List extends React.Component {
componentWillReceiveProps(nextProps) {
if ( !this.props.shouldFetch && nextProps.shouldFetch ) {
// Fetch data here and set it in state, for example
// After fetch, don't forget to call onFetch() to reset the boolean
}
}
... // more code
}
Although this will work, it is not bad to use <App />
as the source of data. This way you can abstract pure components that only handles UI but have no network logic. This is often a good model and helps you to reuse components in the future.
Upvotes: 3