2

My component renders 4 times and it seems to be caused by fetching and multiple setState functions. How can I make it use just one setState() including all fetched data?

I have already tried to create one function instead of one, create three variables to store fetch results and pass them to setState but it did not help me. Thanks in advance!

class DuelList extends React.Component {
    state = {
        duels: [],
        users: [],
        datasets: []
    };

    fetchDuels = () => {
        axios.get("http://127.0.0.1:8000/api/duel/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
            .then(res => {
                this.setState({
                    duels: res.data
                });
            });
    };

    fetchUsers = () => {
        axios.get("http://127.0.0.1:8000/api/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
            .then(res => {
                this.setState({
                    users: res.data
                });
            });
    };

    fetchDatasets = () => {
        axios.get("http://127.0.0.1:8000/api/dataset/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
            .then(res => {
                this.setState({
                    datasets: res.data
                });
            });
    };


    componentDidMount() {
        this.fetchDuels();
        this.fetchUsers();
        this.fetchDatasets();
    }


    render() {
        return (
            <div>
                <Duels data={this.state.duels}/> <br/>
                <h2> Add duel </h2>
                <AddDuelForm users={this.state.users} datasets={this.state.datasets} requestType="post" articleID={null}
                             btnText="Challenge"/>
            </div>
        );
    }
}

export default DuelList;```


2 Answers 2

3

You would need to group and resolve all the promises together:

    fetchDuels = () => {
        return axios.get("http://127.0.0.1:8000/api/duel/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
    };

    fetchUsers = () => {
        return axios.get("http://127.0.0.1:8000/api/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
    };

    fetchDatasets = () => {
        return axios.get("http://127.0.0.1:8000/api/dataset/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})
    };


    componentDidMount() {
        const promises = [this.fetchDuels(), this.fetchUsers(), this.fetchDatasets()];

        Promise.all(promises).then(([ duelsReponse, usersResponse, datasetsReponse ]) => {
            this.setState({ duels: duelsReponse.data, users: usersReponse.data, datasets: datasetsResponse.data });
        });
    }

This way, you reduce the number setState calls.

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

4 Comments

thanks! that has helped a bit but still the components renders twice, what should be my next step?
it will always render at least twice, because your doing asynchronous calls. it will render with no data, and then again when data arrives.
ok, but what is the approach when one fetch function url depends on another fetch function response?
then, you need to chain promises.
1

Make use of Promise.all and setState once all the apis resulted in success response like

class DuelList extends React.Component {
    state = {
        duels: [],
        users: [],
        datasets: []
    };

    fetchDuels = () => {
        return axios.get("http://127.0.0.1:8000/api/duel/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})

    };

    fetchUsers = () => {
        return axios.get("http://127.0.0.1:8000/api/user/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})

    };

    fetchDatasets = () => {
        return axios.get("http://127.0.0.1:8000/api/dataset/",
            {'headers': {'Authorization': `Token ${localStorage.getItem('token')}`}})

    };


    componentDidMount() {
        Promise.all([this.fetchDuels(), this.fetchUsers(), this.fetchDatasets()]).then(([duels, users, datasets]) => {
            this.setState({
                 duels,
                 users,
                 datasets
            })
        });
    }


    render() {
        return (
            <div>
                <Duels data={this.state.duels}/> <br/>
                <h2> Add duel </h2>
                <AddDuelForm users={this.state.users} datasets={this.state.datasets} requestType="post" articleID={null}
                             btnText="Challenge"/>
            </div>
        );
    }
}

export default DuelList;

Comments

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.