0

I'm having issues with setting this.setState from within my API call. If I console.log the stocks array inside the axios call the data is available in the array. It is not available outside if it.

Is the problem because this.setState is merging objects? I'm having a hard time conceptualizing what is happening here. How do I fix this problem so I can pass the contents to props?

import React, { Component } from 'react';
import axios from 'axios';

import SearchBar from './components/search_bar';
import StockList from './components/StockList';
import './App.css';

class App extends Component {
constructor() {
super();

this.state = {
  stocks: [],
  term: null,
  value: ''
};

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

handleChange(e) {
this.setState({
  value: e.target.value
});
}

handleClick(e) {
if(e) e.preventDefault();
this.setState({
  value: '',
  term: this.state.value
});

let term = this.state.value;
const key = 'F41ON15LGCFM4PR7';
const url = `https://www.alphavantage.co/query?function=BATCH_STOCK_QUOTES&symbols=${term}&apikey=${key}`;

axios.get(axios.get(url)
.then(res => {
  let stocks = Array.from(res.data['Stock Quotes']).map((stock) => [{symbol: stock['1. symbol'], price: stock['2. price'], volume: stock['3. volume'], timestamp: stock['4. timestamp']}]);

  this.setState((state, props) => {
    return [...this.state.stocks]
  })
})
.catch(error => console.log(error))
)
}

render () {
let stocks = this.state.stocks;
const value = this.state.value;
return (
  <div className="App">
    <h1>Stock Search</h1>
    <SearchBar value={ value }
               onChange={ this.handleChange }
               onClick={ this.handleClick }/>
    <StockList stockItems={ stocks }/>
  </div>
);
}
}

export default App;

1 Answer 1

2

Your setState there is the issue, it's messing up the structure of your state.

this.setState((state, props) => {
    return [...this.state.stocks]
});

Should be either:

this.setState({
    // set stocks to that array you parsed from the axios response
    stocks
});

or

this.setState((state, props) => {
    return {
        ...state,
        // set stocks to that array you parsed from the axios response
        stocks
    };
});

I suggest that because you're accessing the stocks via this.state.stocks in your render

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

2 Comments

Thank you! Just learned something new! Putting spread operator on state like that.
this.setState({ stocks }) and this.setState((state) => ({ ...state, stocks })) are equivalent; setState automatically spreads the update with current state. I would always choose the first since it's simpler.

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.