Let's say I'm having a Parent Component providing a Context which is a Store Object. For simplicity lets say this Store has a value and a function to update this value
class Store {
// value
// function updateValue() {}
}
const Parent = () => {
const [rerender, setRerender] = useState(false);
const ctx = new Store();
return (
<SomeContext.Provider value={ctx}>
<Children1 />
<Children2 />
.... // and alot of component here
</SomeContext.Provider>
);
};
const Children1 = () => {
const ctx = useContext(SomeContext);
return (<div>{ctx.value}</div>)
}
const Children2 = () => {
const ctx = useContext(SomeContext);
const onClickBtn = () => {ctx.updateValue('update')}
return (<button onClick={onClickBtn}>Update Value </button>)
}
So basically Children1 will display the value, and in Children2 component, there is a button to update the value.
So my problem right now is when Children2 updates the Store value, Children1 is not rerendered. to reflect the new value.
One solution on stack overflow is here. The idea is to create a state in Parent and use it to pass the context to childrens. This will help to rerender Children1 because Parent is rerendered.
However, I dont want Parent to rerender because in Parent there is a lot of other components. I only want Children1 to rerender.
So is there any solution on how to solve this ? Should I use RxJS to do reative programming or should I change something in the code? Thanks
You can use context like redux lib, like below
This easy to use and later if you want to move to redux you change only the store file and the entire state management thing will be moved to redux or any other lib.
Running example: https://stackblitz.com/edit/reactjs-usecontext-usereducer-state-management
Article: https://rsharma0011.medium.com/state-management-with-react-hooks-and-context-api-2968a5cf5c83
Reducers.js
import { combineReducers } from "./Store";
const countReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export default combineReducers({ countReducer });
Store.js
import React, { useReducer, createContext, useContext } from "react";
const initialState = {};
const Context = createContext(initialState);
const Provider = ({ children, reducers, ...rest }) => {
const defaultState = reducers(undefined, initialState);
if (defaultState === undefined) {
throw new Error("reducer's should not return undefined");
}
const [state, dispatch] = useReducer(reducers, defaultState);
return (
<Context.Provider value={{ state, dispatch }}>{children}</Context.Provider>
);
};
const combineReducers = reducers => {
const entries = Object.entries(reducers);
return (state = {}, action) => {
return entries.reduce((_state, [key, reducer]) => {
_state[key] = reducer(state[key], action);
return _state;
}, {});
};
};
const Connect = (mapStateToProps, mapDispatchToProps) => {
return WrappedComponent => {
return props => {
const { state, dispatch } = useContext(Context);
let localState = { ...state };
if (mapStateToProps) {
localState = mapStateToProps(state);
}
if (mapDispatchToProps) {
localState = { ...localState, ...mapDispatchToProps(dispatch, state) };
}
return (
<WrappedComponent
{...props}
{...localState}
state={state}
dispatch={dispatch}
/>
);
};
};
};
export { Context, Provider, Connect, combineReducers };
App.js
import React from "react";
import ContextStateManagement from "./ContextStateManagement";
import CounterUseReducer from "./CounterUseReducer";
import reducers from "./Reducers";
import { Provider } from "./Store";
import "./style.css";
export default function App() {
return (
<Provider reducers={reducers}>
<ContextStateManagement />
</Provider>
);
}
Component.js
import React from "react";
import { Connect } from "./Store";
const ContextStateManagement = props => {
return (
<>
<h3>Global Context: {props.count} </h3>
<button onClick={props.increment}>Global Increment</button>
<br />
<br />
<button onClick={props.decrement}>Global Decrement</button>
</>
);
};
const mapStateToProps = ({ countReducer }) => {
return {
count: countReducer.count
};
};
const mapDispatchToProps = dispatch => {
return {
increment: () => dispatch({ type: "INCREMENT" }),
decrement: () => dispatch({ type: "DECREMENT" })
};
};
export default Connect(mapStateToProps, mapDispatchToProps)(
ContextStateManagement
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With