Last active
June 27, 2020 18:02
-
-
Save VineetKumarKushwaha/dacc8c122a4647c9ad077c53ef38d97d to your computer and use it in GitHub Desktop.
React Context Provider Pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useEffect } from "react"; | |
const initialState = { | |
user: null, | |
loading: false, | |
errorMessage: "" | |
}; | |
const UserContext = React.createContext(); | |
const userReducer = (state, action) => { | |
switch (action.type) { | |
case "loading": { | |
return { ...state, loading: true }; | |
} | |
case "fetched": { | |
return { | |
...state, | |
loading: false, | |
user: action.payload | |
}; | |
} | |
case "failed": { | |
return { | |
...state, | |
loading: false, | |
errorMessage: action.payload | |
}; | |
} | |
case "updateName": { | |
return { | |
...state, | |
user: { ...state.user, name: action.payload } | |
}; | |
} | |
case "updatePhone": { | |
return { | |
...state, | |
user: { ...state.user, phone: action.payload } | |
}; | |
} | |
case "updateAddress": { | |
return { | |
...state, | |
user: { | |
...state.user, | |
address: { ...state.user.address, ...action.payload } | |
} | |
}; | |
} | |
default: { | |
throw new Error(`Unhandled action type: ${action.type}`); | |
} | |
} | |
}; | |
const UserProvider = ({ children }) => { | |
const [state, dispatch] = React.useReducer(userReducer, initialState); | |
useEffect(() => { | |
(async () => { | |
dispatch({ type: "loading" }); | |
try { | |
const user = await new Promise((resolve, reject) => { | |
setTimeout(() => { | |
resolve({ | |
name: "Test User", | |
gender: "Male", | |
phone: "+910000000000", | |
address: { | |
building: "2030", | |
street: "something something", | |
location: "Some", | |
country: "India" | |
} | |
}); | |
}, Math.ceil(Math.random() * 1000)); | |
}); | |
dispatch({ type: "fetched", payload: user }); | |
} catch (error) { | |
dispatch({ type: "failed", errorMessage: "Not able to fetch user" }); | |
} | |
})(); | |
}, [dispatch]); | |
return ( | |
<> | |
{state.loading && <h1>Fetching User...</h1>} | |
{state.errorMessage && <h1>{state.errorMessage}</h1>} | |
{state.user && ( | |
<UserContext.Provider value={{ state, dispatch }}> | |
{children} | |
</UserContext.Provider> | |
)} | |
</> | |
); | |
}; | |
const useUser = () => { | |
const context = React.useContext(UserContext); | |
if (context === undefined) { | |
throw new Error("Error"); | |
} | |
return context; | |
}; | |
export { UserProvider, useUser }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react"; | |
import { useUser, UserProvider } from "./user-context"; | |
const Address = () => { | |
const { | |
state: { | |
user: { address } | |
} | |
} = useUser(); | |
return ( | |
<> | |
<h3> | |
{address.building}, {address.street} | |
</h3> | |
<h3> | |
{address.location}, {address.country} | |
</h3> | |
</> | |
); | |
}; | |
const Information = () => { | |
const { | |
state: { user } | |
} = useUser(); | |
return ( | |
<h2> | |
{user.name}, {user.gender}, {user.phone} | |
</h2> | |
); | |
}; | |
const Display = () => { | |
return ( | |
<div className="displayCard"> | |
<Information /> | |
<Address /> | |
</div> | |
); | |
}; | |
const EditableInformation = () => { | |
const { | |
state: { user }, | |
dispatch | |
} = useUser(); | |
return ( | |
<div className="personal"> | |
Name:{" "} | |
<input | |
value={user.name} | |
type="text" | |
onChange={e => | |
dispatch({ type: "updateName", payload: e.target.value }) | |
} | |
/> | |
Name:{" "} | |
<input | |
type="text" | |
value={user.phone} | |
onChange={e => | |
dispatch({ type: "updatePhone", payload: e.target.value }) | |
} | |
/> | |
</div> | |
); | |
}; | |
const Editable = () => { | |
return ( | |
<div className="editable"> | |
<EditableInformation /> | |
</div> | |
); | |
}; | |
export default function App() { | |
return ( | |
<div className="App"> | |
<UserProvider> | |
<Display /> | |
<Editable /> | |
</UserProvider> | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Working Example is here
In this, I have implemented both the things, you can read the user information through the context API, and also you can update it though I would not suggest to do the write operation like this.
IMO, Context API is very useful for a read-only state like logged in user information or preferred language across the application.
Although when we allow update from the child components, it might create a mess plus it would cause difficulties while debugging like who changed the state and when.
Click here for more information