How to call API and render a new component

Viewed 48

What would be a way to call an API in a component class (do not use a functional component) and render the received data in a new component. I am asking for the order of operation to setState. My current solution includes setState and a function as a second argument that set anther state. Function getStockInfo calls API and then I want to render the GetQuote component switching showComponent to true. Note that in ComponentDidMount I call an initial API. Please let me know if this is a valid solution or there is a neater way.

class Portfolio extends Component {
  constructor(props) {
    super(props);
    this.state = {
      res: " ",
      data: [],
      showComponent: false,
    };

    this.showStockiaDetails = this.showStockDetails.bind(this);
    this.getStockInfo = this.getStockInfo.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }
  async getStockInfo(item) {
    const stock = item.symbol;
    const API_KEY = "1D";
    const PATH = `https://www.alphavantage.co/query?function=OVERVIEW&symbol=${stock}&apikey=${API_KEY}`;
    await axios
      .get(PATH)
      .then((response) => {
        this.setState({ res: response.data }, () => this.showStockDetails());
        console.log(response.data);
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  handleClick(item) {
    this.getStockInfo(item);
  }

  showStockDetails() {
    console.log("-->", this.state.res);
    this.setState({ showComponent: true });
  }

  componentDidMount() {
    axios
      .get("http://127.0.0.1:8000/api/data")
      .then((response) => {
        this.setState({ data: response.data });
      })
      .catch(function (error) {
        console.log(error);
      });
  }

  render() {
    return (
      <div className="container">
        <h1>Day Eight</h1>
        <div className="row col-12">
          <div className="col-md-5 col-lg-4 ">
            <ul className="list-group">
              {this.state.dayeightData.map((s) => (
                <li
                  key={s.id}
                  onClick={() => this.handleClick(s)}
                  className="list-group-item"
                  aria-current="true"
                >
                  {s.symbol}
                </li>
              ))}
            </ul>
          </div>
          <div className="col-md-7 col-lg-8 order-md-last">
            {this.state.showComponent ? (
              <GetQuote stock={this.state.res} />
            ) : null}
          </div>
        </div>
      </div>
    );
  }
}
export default Portfolio;
1 Answers

You did it right. There would be many other alternatives too depending on what GetQuote component is rendering. To make it look a little bit more cleaner you can do something like this:

{
this.state.res ? <GetQuote stock={this.state.res} /> : ''
}

But make sure to initialize res as "" (without any space) as "" will be false and " " will be true. In that way, you don't really have to call showStockDetails function.

Related