5

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.

4
  • Are you using Redux? If so, you can dispatch an action from <Search /> Commented Jan 5, 2017 at 20:49
  • @OmriAharon Unfortunately not, plain React for now. Commented Jan 5, 2017 at 20:50
  • Then since the only way components receive information (in the "React way") is state/props, you pretty much covered both options. I'd use your first option that you got to work. By the way - <Search /> seems like a perfectly fine place to call this API (or at least trigger it), and <List /> should be perfectly happy with just receiving and displaying data. Commented Jan 5, 2017 at 20:55
  • A third option might be to fetch in the <Search /> component, then call a function in <App /> with the data you received, which would in turn just pass it to <List />, so basically <Search /> handles the call instead of <App />. Commented Jan 5, 2017 at 20:57

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.