Skip to content

Instantly share code, notes, and snippets.

@kpunith8
Last active October 10, 2023 03:17
Show Gist options
  • Save kpunith8/2bb2b62620b6cf78f71d4164a8ecb420 to your computer and use it in GitHub Desktop.
Save kpunith8/2bb2b62620b6cf78f71d4164a8ecb420 to your computer and use it in GitHub Desktop.
Using query and route params with useContext() Hook
import React, {useState} from 'react'
import RouteContext, {EMPTY_ROUTE} from './route-context'
const App = props => {
const [route, setRoute] = useState(EMPTY_ROUTE)
useEffect(() => {
// Logic to update the setRoute() based on the current route
// route object has params and query keys, update them accordingly
// or pass setRoute setter as vlaue to th Provider
// <RouteContext.Provider value={{route, setRoute}}>, whenever you call setRoute in
// a child component it will re-render the app depending on route params (only rerenders the part of the UI, which
// makes the call to specific API based on useEffect)
}, [])
return (
<RouteContext.Provider value={route}>
<Layout {props...} />
</RouteContext.Provider>
)
}
export default App
import React, { useContext, useEffect, useState } from "react";
const EMPTY_ROUTE = { params: {}, query: {} };
const UserContext = React.createContext();
const UserInfo = () => {
const { route, setRoute } = useContext(UserContext);
return (
<>
<pre>{JSON.stringify(route, null, 2)}</pre>
<button
onClick={() =>
// Try removing the name property on query and see how it re-renders the UI
setRoute({ params: "1", query: { id: 1, name: "Punith" } })
}
>
New User
</button>
</>
);
};
const UserDetails = () => {
const [userDetails, setUserDetails] = useState("");
const { route } = useContext(UserContext);
// This useEffect can invoke any async call, including calling an websocket
// so that all the users using this UI will be updated.
useEffect(() => {
console.log("set user details");
// This useEffect() will re-run only if you update route.query.name
// property in UserInfo's onClick listener. Remove updating "name"
// property on query key to see the re-rendering in action
setUserDetails(route.query.name);
}, [route.query.name]);
return (
<>
<div>{userDetails}</div>
</>
);
};
const UseContextSample = (props) => {
const [route, setRoute] = useState(EMPTY_ROUTE);
return (
<UserContext.Provider value={{ route, setRoute }}>
<UserInfo {...props} />
<UserDetails />
</UserContext.Provider>
);
};
export default UseContextSample;
import React, {useContext} from 'react'
import RouteContext from './route-context'
// actions coming from where the useService() and actions are defined as per this ariticle
// https://pktechblog.netlify.app/blog/post/how-to-manage-complex-ui-state-with-use-reducer
const Layout = ({actions} ...props) => {
const route = useContext(RouteContext)
useEffect(() => {
// Call the appropriate action to fetch the data whenever there is a changes to
// query or param
// Whenever the readUserInfo() updates the state we can re-render the UI
// to all the users or this Layout or any child component.
// It only make the call to service actions only if there is a change to query or param
// I'm assuming that we are receving query paramsfrom libraries called react-router-dom
// It can be any random object that controls the data fetching or mimics the user action.
actions.readUserInfo({query: route.query, params: route.params})
}, [route.query, route.params])
render (
// Because we are using context API, we can make change in any
// child component, pass down the actions if you want to make a API
// call or data fetch from anywhere down the DOM tree
<AnotherComponent {...{actions, ...props}}/>
)
}
export default Layout
import React from 'react'
export const EMPTY_ROUTE = {params: {}, query: {}}
const RouteContext = React.createContext(EMPTY_ROUTE)
export default RouteContext
@kpunith8
Copy link
Author

kpunith8 commented May 21, 2021

React hooks library, https://github.com/streamich/react-use it has so many useful hooks and reduces lot of boilerplate in your code base

@kpunith8
Copy link
Author

Added working example, complete-working-sample.js please refer and implement as required

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment