0
votes

I have a React Context, so I can save some data and reuse it where I want in my React-Project. Here is the code I'm working on:

import React, { useState, createContext } from "react"
import apiRequest from "../axios"
import { getCookie } from "../Utils"
import jwt_decode from "jwt-decode"

export const UserContext = React.createContext()

export const UserProvider = (props) => {
    const [value, setValue] = useState({
        loading: false,
        isLoggedIn: false,
        userId: "",
        username: ""
    })

    const updateData = (toUpdate) => {
        setValue({...value, ...toUpdate})
    }

    const fetchUser = async (userId, key) => {
        await apiRequest("get", "/user/" + userId, null, () => {}, (data) => {
            updateData({
                loading: false,
                isLoggedIn: true,
                userId: userId,
                username: data.user.username
            })

        }, (errMessage) => {

            updateData({
                loading: false
            })

        }, key)
    }

    // load user data if access token is set
    const accessToken = getCookie("access")
    if (accessToken && !value.loggedIn && !value.loading) {
        updateData({ loading: true })
        const { sub: userId } = jwt_decode(accessToken)
        fetchUser(userId, accessToken)              // if I comment this out, then no infinite loop
    }

    const methods = {
        fetchUser,
        updateData
    }

    return (
        <UserContext.Provider value={[value, methods]}>
            {props.children}
        </UserContext.Provider>
    )
}

I have commented the line, where it creates this loop. Can anyone tell me why it is behaving like that?

1

1 Answers

0
votes

You need to do the fetch request in the useEffect so that it is fired only when the component is mounted or when the cookie value changes.

Try this;

import React, { useState, createContext, useEffect } from "react"
import apiRequest from "../axios"
import { getCookie } from "../Utils"
import jwt_decode from "jwt-decode"

export const UserContext = React.createContext()

export const UserProvider = (props) => {
    const [value, setValue] = useState({
        loading: false,
        isLoggedIn: false,
        userId: "",
        username: ""
    })

    const updateData = (toUpdate) => {
        setValue({...value, ...toUpdate})
    }

    const fetchUser = async (userId, key) => {
        updateValue({ loading: true });
        await apiRequest("get", "/user/" + userId, null, () => {}, (data) => {
            updateData({
                loading: false,
                isLoggedIn: true,
                userId: userId,
                username: data.user.username
            })

        }, (errMessage) => {
            updateData({loading: false})
        }, key)
    }

    // load user data if access token is set
    const accessToken = getCookie("access")
    useEffect(() => {
      if (accessToken && !value.loggedIn && !value.loading) {
        const { sub: userId } = jwt_decode(accessToken)
        fetchUser(userId, accessToken);
      }
    }, [accessToken]);

    const methods = {
        fetchUser,
        updateData
    }

    return (
        <UserContext.Provider value={[value, methods]}>
            {props.children}
        </UserContext.Provider>
    )
}