ReactJS display fetch response onClick

Viewed 40577

Im working on a ReactJS project where you can generate a random activity when pressing the generate button. Im doing a fetch to my api to display some data from it. This works fine. Now I want to do the fetch and display the returned data every time I click the generate button (which is in the home component). So the generate button has to do a new fetch and refresh the component. Also it has to be empty on default. I searched a while and can't find a relevant answer. Can some of you guys help me out? Thanks.

fetch component

import React from "react";

export class ItemLister extends React.Component {
    constructor() {
        super();
        this.state = { suggestion: "" };
    }

    componentDidMount() {
        fetch("......./suggestions/random", {
            method: "GET",
            dataType: "JSON",
            headers: {
                "Content-Type": "application/json; charset=utf-8"
            }
        })
            .then(resp => {
                return resp.json();
            })
            .then(data => {
                this.setState({ suggestion: data.suggestion });
            })
            .catch(error => {
                console.log(error, "catch the hoop");
            });
    }

    render() {
        return <h2>{this.state.suggestion}</h2>;
    }
}

home component

import React from "react";
import { ItemLister } from "./apiCall";

export class Home extends React.Component {
    constructor(props) {
        super(props);
        console.log();
        window.sessionStorage.setItem("name", this.props.params.name);
        window.sessionStorage.setItem("token", this.props.params.token);
    }

    render() {
        return (
            <div className="contentContainer AD">
                <table>
                    <thead>
                        <tr>
                            <th>
                                <p>Het is heel leuk als het werkt!</p>
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>
                                <ItemLister />
                            </td>
                        </tr>
                    </tbody>
                </table>
                <div className="container center">
                    <button>GENERATE</button>
                    <button>SAVE</button>
                    <button>MATCH</button>
                </div>
            </div>
        );
    }
}
2 Answers

I would say that you move your fetch logic to home component and maintain a state in home component just like you are doing in Itemlister component. Then all you have to do is pass your state to Itemlister component. Your home component will look like this

export class Home extends React.Component {
constructor(props) {
    super(props)
    this.state = {suggestion: ""}
    ...
}

componentDidMount(){
  // For initial data
  this.fetchData();
}

fetchData = () => {
  fetch("......./suggestions/random", {
    method: "GET",
    dataType: "JSON",
    headers: {
      "Content-Type": "application/json; charset=utf-8",
    }
  })
  .then((resp) => {
    return resp.json()
  }) 
  .then((data) => {
    this.setState({ suggestion: data.suggestion })                    
  })
  .catch((error) => {
    console.log(error, "catch the hoop")
  })
}

render() {
    return (
        ...
                <tbody >
                   // Pass state to itemlister like this
                    <tr><td><ItemLister suggestion={this.state.suggestion}/></td></tr>
                </tbody>
            </table>
            <div className="container center">
                // Add event handler here. On every click it will fetch new data
                <button onClick={this.fetchData}>GENERATE</button>
                <button>SAVE</button>
                <button>MATCH</button>
            </div>
        </div>
    )
  }
}

And your ItemLister component has the responsibility to display the data via props.

export class ItemLister extends React.Component {
    constructor() {
    super();
    }

    render() {
    return(
      <h2> 
        {this.props.suggestion}
      </h2>
      )
     }
    } 

As per the suggestion by dubes in comment, If you don't want to maintain any state in this component then you can make this functional component like this

function ItemLister(props) {
  return <h2> 
            {props.suggestion}
          </h2>;
}

I am not quite sure if I understood you correctly... but since you're adding your fetch inside a react extended class, you can render it inside the home component like so:

  state = {
    visible: false
  }

  generateItem() {
    if (this.state.visible) {
      return <ItemLister />
    }
    return <h2>nothing to show</h2>
  }

  render() {
    return(
      <div>
        <button onClick={() => this.setState({visible: true})}>Click</button>
        {this.generate()}
      </div>
    )
  }

The onClick function will update the state every time the user clicks on it and a new rerender will occur thus calling generateItem again with a new random word.

Hope this is what you were searching for.

Related