1

I'm creating a hackernews-clone using this API

This is my component structure

-main
   |--menubar
   |--articles
   |--searchbar

Below is the code block which I use to fetch the data from external API.

componentWillReceiveProps({search}){
    console.log(search);
}

componentDidMount() {
    this.fetchdata('story');
}

fetchdata(type = '', search_tag = ''){
    var url = 'https://hn.algolia.com/api/v1/search?tags=';
    fetch(`${url}${type}&query=${search_tag}`)
    .then(res => res.json())
    .then(data => {
        this.props.getData(data.hits);
    });
}

I'm making the API call in componentDidMount() lifecycle method(as it should be) and getting the data correctly on startup. But here I need to pass a search value through searchbar component to menubar component to do a custom search. As I'm using only react (not using redux atm) I'm passing it as a prop to the menubar component. As the mentioned codeblock if I search react and passed it through props, it logs react once (as I'm calling it on componentWillReceiveProps()). But if I run fetchData method inside componentWillReceiveProps with search parameter I receive it goes an infinite loop. And it goes an infinite loop even before I pass the search value as a prop.

So here, how can I call fetchdata() method with updating props ?

I've already read this stackoverflow answers but making an API call in componentWillReceiveProps doesn't work.

So where should I call the fetchdata() in my case ? Is this because of asynchronous ?

Update : codepen for the project

Thidasa Pankaja
  • 930
  • 8
  • 25
  • 44

3 Answers3

3

You can do it by

componentWillReceiveProps({search}){
  if (search !== this.props.search) {
    this.fetchdata(search);
  }
}

but I think the right way would be to do it in componentDidUpdate as react docs say

This is also a good place to do network requests as long as you compare the current props to previous props (e.g. a network request may not be necessary if the props have not changed).

componentDidMount() {
  this.fetchdata('story');
}

componentDidUpdate(prevProps) {
  if (this.props.search !== prevProps.search) {
    this.fetchdata(this.props.search);
  }
}
Qwertiy
  • 19,681
  • 15
  • 61
  • 128
  • Thanks a lot. This works. But why you mention the second approach as the right way ? – Thidasa Pankaja Mar 07 '18 at 09:59
  • 1
    As for me, `componentWillReceiveProps` is some kind of preparation, not a place to execute business logic. But there can be other mentions. – Qwertiy Mar 07 '18 at 10:01
1

Could it be that inside this.props.getData() you change a state value, which is ultimately passed on as a prop? This would then cause the componentWillReceiveProps function to be re-called. You can probably overcome this issue by checking if the search prop has changed in componentWillReceiveProps:

componentWillReceiveProps ({search}) {
  if (search !== this.props.search) {
    this.fetchdata(search);
  }
}
Nsevens
  • 2,588
  • 1
  • 17
  • 34
1

Why not just do this by composition and handle the data fetching in the main HoC (higher order component).

For example:

class SearchBar extends React.Component {
  handleInput(event) {
    const searchValue = event.target.value;
    this.props.onChange(searchValue);
  }

  render() {
    return <input type="text" onChange={this.handleInput} />;
  }
}

class Main extends React.Component {
  constructor() {
    this.state = {
      hits: []
    };
  }

  componentDidMount() {
    this.fetchdata('story');
  }

  fetchdata(type = '', search_tag = '') {
    var url = 'https://hn.algolia.com/api/v1/search?tags=';
    fetch(`${url}${type}&query=${search_tag}`)
      .then(res => res.json())
      .then(data => {
        this.setState({ hits: data.hits });
      });
  }

  render() {
    return (
      <div>
        <MenuBar />
        <SearchBar onChange={this.fetchdata} />
        <Articles data={this.state.hits} />
      </div>
    );
  }
}

Have the fetchdata function in the main component and pass it to the SearchBar component as a onChange function which will be called when the search bar input will change (or a search button get pressed).

What do you think?

sarneeh
  • 1,320
  • 1
  • 12
  • 27
  • Thanks. But I'm thinking of keeping `main` component clean. That's why I'm using the API call on `menubar` component. And I'm little bit new to react. So still HOC is bit confusing to me. Anyway Thanks . – Thidasa Pankaja Mar 07 '18 at 10:01