React passing fetched data to another component

Viewed 6055

Hy!

I am having an issue with my react code. My task is to call from iTunes API which i do with fetch then I process the data. But I cannot save it as a variable to be able to pass it around later.

import React, { Component } from 'react';

class SearchField extends Component{
  constructor(props) {
  super(props);
  this.state = {value: ''};

this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

handleChange = (event) => {
  this.setState({value: event.target.value});
}

handleSubmit = (event) => {
  event.preventDefault();
  fetch(`https://itunes.apple.com/search?media=music&term=${this.state.value.toLowerCase()}`)
  .then((resp) => resp.json())
  .then(searchRes => searchRes.results[0].artistName)
  .catch(err => console.log(err));
}

render() {
return(
  <section className="hero is-primary">
    <div className="hero-body">
      <div className="container">
        <form onSubmit={this.handleSubmit}>
          <input className="input is-primary" type="text" value={this.state.value} onChange={this.handleChange} placeholder="Search for artist" />
          <input className="button is-info" type="submit" value="Search" />
        </form>
      </div>
    </div>
  </section>
)
}
}
export default SearchField;

I'd have to use the fetched data later, i just need the artist name first. If I log the value (searchRes.results[0].artistName, i get the correct value, but if i want to save it for later use i only got empty console.log back. I've tried several approaches but I never get my result back.

Help me out please.

2 Answers

Remember that data flow in React is unidirectional. If you want to share the data around your app the search component should not be the component that fetches the data. That should be left to a parent component (maybe App). That component should have a function that handles the fetch request, and you can then pass a reference to that function down to the search component to call when the button is clicked. Then, once that data is loaded, the parent (App) component can pass all the relevant data down to the child components.

Here's a quick mock-up based on your existing code:

class Search extends {

  constructor(props) {
    super(props);
    this.state = { url: '' };
    this.handleKey = this.handleKey.bind(this);
  }

  handleKey(e) {
    const url = e.target.value;
    this.setState({ url });
  }

  render() {
    const { url } = this.state;

    // grab the function passed down from App
    const { fetchData } = this.props;
    return (
      <input onKeyUp={this.handleKey} value={url} />

      // Call that function with the url when the button is clicked
      <button onClick={() => fetchData(url)}>Click</button>
    )
  }
}


class App extends Component {

  constructor(props) {
    super(props);
    this.state = { data: [] };
    this.fetchData = this.fetchData.bind(this);
  }

  // App contains the fetch method
  fetchData(url) {
    fetch(url)
      .then(res => res.json())

      // Update the App state with the new data
      .then(data => this.setState({ data });
  }

  render() {
    const { data } = this.state;

    // Sanity check - if the state is still empty of data, present
    // a loading icon or something
    if (!data.length) return <Spinner />

    // otherwise return the rest of the app components
    // passing in the fetch method as a prop for the search component
    return (
      <OtherComponent data={data} />
      <Search fetchData={this.fetchData} />
    )
  }
}

Please specify what you mean by

but if i want to save it for later use i only got empty console.log back

I think the correct way to handle your problem is by passing a callback function to your component's props that gets called whenever you press search and a search result is found, like this: https://codesandbox.io/s/xpq171n1vz

Edit: Note that while this answer has been accepted and is a way to solve your problem, Andy's answer contains solid and elaborate advice on how to actually structure your components.

Related