Function passed as parameter takes old store from React Context API

我怕爱的太早我们不能终老 提交于 2020-01-16 09:05:13

问题


When I get 401 status code from backend I run refreshToken method with passing the function where expired token occurred. In refreshToken method I get new token and set in refreshTokenLastFunc property function from parameter.

Then I watch when refreshTokenLastFunc was updated using React useEffect and run once again the function where expired token occurred.

The problem is while I run store.refreshTokenLastFunc() in useEffect, the function in refreshTokenLastFunc property uses old Context API store(so it uses old token not the new one). You can read my comment in useEffect for store.refreshTokenLastFunc.

export const StoreProvider = props => {
const getToken = () => localStorage.getItem("token");

const initState = () => ({
    token: getToken(),
    isAuth: false,
    userRole: "old role",
    mainUrl: MainUrl,
    apiUrl: ApiUrl,
    refreshTokenLastFunc: () => {}
})

const [store, setStore] = useState(initState());


const getUserInfo = async () => {
    if (getToken()) {
        try {
            const apiConfig = {
                method: "GET",
                headers: {
                "Content-Type": "application/json",
                "Authorization": `Bearer ${store.token}`,
                },
            };

            const response = await fetch(`${store.apiUrl}get-me`, apiConfig);
            const responseJson = await response.json();

            if (response.ok) {
                // Update Context API
                setStore({
                    ...store,
                    userRole: responseJson.role,
                    userName: responseJson.name,
                    userGroupId: responseJson.group_id,
                    isAuth: true,
                })

            } else if(response.status === 401) {
                refreshToken(getUserInfo);
            } else {
                throw new Error(`Some error occurred`);
            }
        } catch (error) {
            console.log(error);
        }
    }
}

const refreshToken = async func => {
    try {
        const apiConfig = {
            method: "GET",
            headers: {
                "Accept": "application/json",
                "Authorization": `Bearer ${store.token}`,
            },
        };

        const response = await fetch(`${store.mainUrl}refresh-token`, apiConfig);
        const responseJson = await response.json();

        if (response.ok) {
            // Update token in local storage
            localStorage.setItem("token", responseJson.token);
             // Update Context API
            setStore({
                ...store,
                userRole: 'new role',
                token: responseJson.token,
                refreshTokenLastFunc: func,
            })
        }  else {
            throw new Error(`Some error...`);
        }
    } catch (error) {
        throw error;
    }
}

useEffect(() => {
    getUserInfo();
}, []);

useEffect(() => {
    // If I console log my store before calling function, store is correctly updated, but the function uses old store.
    console.log('store from useEffect: ', store); // store.userRole = 'new role' which is correct
    store.refreshTokenLastFunc(); // store.userRole = 'old role' which should be 'new role'
}, [store.refreshTokenLastFunc]);

return(
    <StoreContext.Provider value={[store, setStore, logout, getUserInfo]}>
        {props.children}
    </StoreContext.Provider>
);

}

来源:https://stackoverflow.com/questions/59488943/function-passed-as-parameter-takes-old-store-from-react-context-api

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!