Search code examples
javascriptreactjssetintervalticker

How to make a Ticker App in React, using default values, that can be dynamically updated by the user


I'm learning React by building a simple Cryptocurrency Ticker:

class Ticker extends Component {
    constructor(props) {
        super(props)

        this.state = {
            currencies: [],
            limit: 12
        }
    }

    getCurrencies = (num) => {
        axios.get(`https://api.coinmarketcap.com/v1/ticker/?limit=${num}`)
            .then(res => this.setState({
                currencies: res.data
            }));
    }

    componentDidMount = () => {
        const { limit } = this.state;
        this.getCurrencies(limit);
        this.tickerTimer = setInterval(() => this.getCurrencies(limit), 10000);
    }

    render() {
        const { currencies } = this.state;
        return (
        <div>
            {currencies.map((currency) => {
                return (
                    <Crypto key={currency.id} currency={currency} />
                )
            })}
        </div>
        );
    }
}
  • getCurrencies() makes a request and populates this.state.currencies array.
  • componentDidMount() makes the initial request for the first render with the default limit of cryptocurrencies (12).
  • setInterval() is set in componentDidMount() to update the data every 10 seconds as soon as the app initially renders.

Everything was running smoothly until I tried to implement an Input Field to allow the user to set his own limit of displayed cryptocurrencies:

handleChange = (e) => {
    this.setState({
        limit: e.target.value
    }, () => {
        this.getCurrencies(this.state.limit);
    })
}
...
render() {
    ....
    <input onChange={this.handleChange} />
}
  • handleChange() passes the input's value to this.state.limit
  • the callback allows me to update the UI dynamicly with the change (that's what I've seen being done to deal with asynchronicity of setState).

The thing is, since componentDidMount() runs only once and doesn't care about the updates on the state, the limit thats set by the user is only temporary. The getCurrencies function is called from componentDidMount() after 10 seconds, and it obviously uses the initial value that's been past originaly (12). I tried to hook the interval in handleChange(), but then the ticker is triggered only if the user inputs a value. I tried doing it in render() as well but it seems bugged.

  • I'd like my app to render and keep updating the data of the right amount of cryptos, regardless if the user changes the amount he wants to display. If he changes the default value, I don't want it to be overwritten by anything else other than himself.

What am I missing ?

Where could I set the Interval ?

Should I use a setInterval method to begin with ?


Solution

  • You just need a small change for getCurrencies and componentDidMount:

    getCurrencies = () => {
        axios.get(`https://api.coinmarketcap.com/v1/ticker/?limit=${this.state.limit}`)
            .then(res => this.setState({
                currencies: res.data
            }));
    },
    
    componentDidMount = () => {
        this.getCurrencies();
        this.tickerTimer = setInterval(() => this.getCurrencies(), 10000);
    }