How can I use an axios get call inside a Context provider in react
Asked Answered
B

1

6

I want to make a call to get the user information and use it in different components throughout the application, so I am using react.Context and I managed to move a string around between components but when I tried to use the axios.get I was not able to get the data to another component, here is the context code:

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

export const userContext = createContext();

export const UserProvider = (props) => {
    const config = {
        headers: {
            'Content-Type': 'application/json',
            'Authorization': `JWT ${localStorage.getItem('access')}`,
            'Accept': 'application/json'
        }
    };
    const res = axios.get(`${process.env.REACT_APP_API_URL}/auth/users/me/`, config)
    return(
    <userContext.Provider value= { res }>{props.children}</userContext.Provider>
    );
} 

can someone please tell me what I did wrong here

Britanybritches answered 15/11, 2020 at 4:43 Comment(1)
Why are you making an API call inside the context provider? You should make the call inside a component and dispatch an action that updates the global state with the data you're fetching from the API.Encumbrancer
C
7

It would be more manageable if you could handle the state in hassle free way. Instead of passing the res which I reckoned going to be your state, directly to the Provider. Which I think, in time, if you have more than one state you want to add to your User context. You gonna need to pass them too as value. That would not be flexible.

I would suggest you to manage them like so:-

  1. Having dedicated User context folder: src/contexts/User
  • src/contexts/User/UserContext (creating User context)
import { createContext } from "react";

export const UserContext = createContext();

  • src/contexts/User/UserReducer (handle state update)
export default (state, action) => {
  switch (action.type) {
    case "SET_USER":
      return {
        ...state,
        user: action.payload
      };
    case "SET_ERROR":
      return {
        ...state,
        error: action.payload.error,
        message: action.payload.message
      };
    case "SET_LOADING":
      return {
        ...state,
        loading: action.payload
      };
    default:
      return state;
  }
};

  • src/contexts/User/UserAction (handle action done to state. Basically anything that you need to make the changes to your state)
import axios from "axios";

// Set Loading
export const setLoading = (dispatch, status) =>
  dispatch({ type: "SET_LOADING", payload: status });

// Set Error
export const setError = (dispatch, error) =>
  dispatch({
    type: "SET_ERROR",
    payload: { error: error.status, message: error.message }
  });

// Set User (get user info)
export const getUser = async dispatch => {
  setLoading(dispatch, true);

  // do fetch
  await axios
    .get(`https://jsonplaceholder.typicode.com/users/1`)
    .then(res => {
      const result = res.data;

      // set user info
      dispatch({
        type: "SET_USER",
        payload: result
      });
    })
    .catch(error => {
      const result = error;

      // set error if has any
      dispatch({
        type: "SET_ERROR",
        payload: {
          error: true,
          message: result
        }
      });
    });
};

  • src/contexts/User/UserState (handle state initialization. You can later add more or initialize more state in const initialState below if you have any. Plus you don't need to add more value in future tho.)
import React, { useContext, useReducer } from "react";
import { UserContext } from "./UserContext";
import UserReducer from "./UserReducer";

export const useUser = () => {
  const { state, dispatch } = useContext(UserContext);
  return [state, dispatch];
};

export const UserState = ({ children }) => {
  const initialState = {
    user: {},
    loading: false,
    error: false,
    message: ""
  };

  const [state, dispatch] = useReducer(UserReducer, initialState);

  return (
    <UserContext.Provider
      value={{
        state: state,
        dispatch: dispatch
      }}
    >
      {children}
    </UserContext.Provider>
  );
};

Then you can use them like so:-

  1. Make sure to encapsulate any component thet you wanna use the User context (this will be in App.js)
  • App.js:-
import React from "react";
import { UserState } from "./contexts/User/UserState";
import Demo from "./Demo";
import "./style.css";

export default function App() {
  return (
    <UserState>
      <Demo />
    </UserState>
  );
}

  1. You can use any state initialized in UserState by using useState:-
  • Demo.js (App.js child component):-
import React, { useEffect } from "react";
import { useUser } from "./contexts/User/UserState";
import { getUser, setLoading } from "./contexts/User/UserAction";
import "./style.css";

const Demo = () => { 
  const [userState, userDispatch] = useUser();
  const { user, loading, error, message } = userState;

  // get user info handler
  const getUserInfoHandler = async () => {
    await getUser(userDispatch);
    setLoading(userDispatch, false);
  };

  // get user info
  useEffect(() => {
    getUserInfoHandler();
  }, []);

  return (
    <div>
      {loading && <p>Loading...</p>}
      {error && <p>{message}</p>}
      <p>User name: {user.name}</p>
    </div>
  );
};

export default Demo;

You may see the working code here in sandbox

Concoct answered 15/11, 2020 at 12:8 Comment(3)
Thank you so much for the long explanation, but I do not think I explained my question correctly, I already have an authentication system and after I get the JWT I use it to get the user information, but I want to use this information in another page and that is why I have been looking into context, I have been looking for a while and I understand how to make a context and a provider but I do not understand how can I update the context data inside a class based react component "class ..... extendes React.component", can you please show me how to use it ?? ThanksBritanybritches
Thanks A lot, how to make PUT POST request can you modify answer to add that as well much appreciatedSunlight
@AshishKamble. You can refer to this example I made here in sandbox. Hope it helpsConcoct

© 2022 - 2024 — McMap. All rights reserved.