Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 4, 2020 10:34 pm GMT

How to manage global data with Context API, without Redux on React

Hi, Taishi here

How do you manage global data on React?
I used to use Redux for that, however, I currently use Context API for that purpose and I don't even install redux and redux-related packages!

2 ways to implement it with Context API

I think there are 2 ways to make it happen.
A simple and complicated one.

I am gonna explain the simple one first

Imagine we want to manage the logged-in user data.

1. Use state variable

First of all, we need a Context component for sure.

I found this way when I was reading next.js/userContext.js at master vercel/next.js

Add userContext.js

Let's make ./src/context/userContext.js.

// File: ./src/context/userContext.jsimport React, { useState, useEffect, createContext, useContext } from 'react';import firebase from '../firebase/clientApp';export const UserContext = createContext();export default function UserContextComp({ children }) {  const [user, setUser] = useState(null);  const [loadingUser, setLoadingUser] = useState(true); // Helpful, to update the UI accordingly.  useEffect(() => {    // Listen authenticated user    const unsubscriber = firebase.auth().onAuthStateChanged(async (user) => {      try {        if (user) {          // User is signed in.          const { uid, displayName, email, photoURL } = user;          // You could also look for the user doc in your Firestore (if you have one):          // const userDoc = await firebase.firestore().doc(`users/${uid}`).get()          setUser({ uid, displayName, email, photoURL });        } else setUser(null);      } catch (error) {        // Most probably a connection error. Handle appropriately.      } finally {        setLoadingUser(false);      }    });    // Unsubscribe auth listener on unmount    return () => unsubscriber();  }, []);  return (    <UserContext.Provider value={{ user, setUser, loadingUser }}>      {children}    </UserContext.Provider>  );}// Custom hook that shorhands the context!export const useUser = () => useContext(UserContext);

As you can see, UserContextComp component has user state variable.

const [user, setUser] = useState(null);

We store the user data in this user variable and update it with setUser() function.

Edit index.js

Now we have to use the UserContextComp component to consume it!
Edit ./src/index.js like below.

// File: ./src/index.jsimport React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import * as serviceWorker from './serviceWorker';import UserProvider from './context/userContext';ReactDOM.render(  <React.StrictMode>    <UserProvider>      <App />    </UserProvider>  </React.StrictMode>,  document.getElementById('root'),);// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://bit.ly/CRA-PWAserviceWorker.unregister();

Now we can use user variable and update it with setuser() function everywhere

How to consume it

Import the useUser function from the ./src/context/userContext.js and get the variable you need.
In this case, we take loadingUser, user, and setUser.

import React from 'react';import { useUser } from '../context/userContext';const MyComponent = () => {  const { loadingUser, user, setUser } = useUser();  return (    <>      {loadingUser ? (        <div>loading</div>      ) : (        <div>Welcome, {user.displayName}</div>      )}    </>  );};export default MyComponent;

Please just use setUser if you need to update the user data just like when you update the usual state variable.

2. Use dispatch and reducer (more Redux way)

In this way, we use useContext with useReducer hook.

I feel like this way is Redux without Redux
Sure, Redux uses Context API inside itself.

By the way. I made an example app here.
Please take a look at this if you wanna make it happen on your local environment.

Context API with useReducer

This is a demo app to show how Context API x useReducer work

Screen Shot 2563-10-03 at 18 04 06

1. Set your firebase project

Please edit ./src/firebase.js.

2. yarn start

That's it!

Anyway, let's dive into it!

Add ./src/context/reducer.js

If you are familiar with Redux, you can understand this with ease.

Now we are gonna define the reducer function and initialState.
The default value of user is null.

// File: ./src/context/reducer.jsexport const initialState = {  user: null,};export const actionTypes = {  SET_USER: 'SET_USER',};const reducer = (state, action) => {  switch (action.type) {    case actionTypes.SET_USER:      return {        ...state,        user: action.user,      };    default:      return state;  }};export default reducer;

Make ./src/context/StateProvider.js

// File: ./src/context/StateProvider.js`import React, { createContext, useContext, useReducer } from 'react';export const StateContext = createContext([]);export const StateProvider = ({ reducer, initialState, children }) => (  <StateContext.Provider value={useReducer(reducer, initialState)}>    {children}  </StateContext.Provider>);export const useStateValue = () => useContext(StateContext);

Set the Provider in ./src/index.js

Because of this, we can consume the StateContext component everywhere!

// File: ./src/index.jsimport React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import * as serviceWorker from './serviceWorker';+ import { StateProvider } from './context/StateProvider';+ import reducer, { initialState } from './context/reducer';ReactDOM.render(  <React.StrictMode>+    <StateProvider initialState={initialState} reducer={reducer}>      <App />+    </StateProvider>  </React.StrictMode>,  document.getElementById('root'),);// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://bit.ly/CRA-PWAserviceWorker.unregister();

Now display the logged in user's name!

Make a Auth component and use it in App.js like below.

We need login/logout methods (handleLogin, handleLogout) to handle onclick events, so make them as well.

// File: ./src/App.jsimport React from 'react';import Auth from './Auth';import { auth, provider } from './firebase';import { useStateValue } from './context/StateProvider';import { actionTypes } from './context/reducer';import './App.css';function App() {  const [state, dispatch] = useStateValue();  const handleLogin = async () => {    try {      const result = await auth.signInWithPopup(provider);      dispatch({        type: actionTypes.SET_USER,        user: result.user,      });    } catch (err) {      alert(err.message);    }  };  const handleLogout = async () => {    await auth.signOut();    dispatch({      type: actionTypes.SET_USER,      user: null,    });  };  return (    <Auth>      <div className="App">        <header className="App-header">          <div>{state.user?.displayName}</div>          {state.user ? (            <button onClick={handleLogout}>Logout</button>          ) : (            <button onClick={handleLogin}>Login</button>          )}        </header>      </div>    </Auth>  );}export default App;

As the reference says, useReducer returns state and dispatch.

An alternative to useState. Accepts a reducer of type (state, action) => newState, and returns the current state paired with a dispatch method. (If youre familiar with Redux, you already know how this works.)

That's why we can get variables like this.

useStateValue() returns useContext(StateContext), and this returns useReducer(reducer, initialState).

const [state, dispatch] = useStateValue();

Now you see like this and you can login/logout.

Login

If you logged in successfully, you can see your name as below.

When the value of state.user is set, your name will be shown.

<div>{state.user?.displayName}</div>

Logout

Note

I think 2. Use dispatch and reducer (more Redux way) may look complicated to you, but we can easily understand what kind of data this app manages globally in initialState. In this example, we manage only user variable globally, but imagine if we manage like 10 variables

Hope this helps.


Original Link: https://dev.to/taishi/how-to-manage-global-data-with-context-api-not-redux-on-react-20m7

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To