There are some ways to avoid re-renders, also make your state management "redux-like". I will show you how I've been doing, it far from being a redux, because redux offer so many functionalities that aren't so trivial to implement, like the ability to dispatch actions to any reducer from any actions or the combineReducers and so many others.
export const reducer = (state, action) => {
...
};
export const AppContext = React.createContext({someDefaultValue})
export function ContextProvider(props) {
const [state, dispatch] = useReducer(reducer, {
someValue: someValue,
someOtherValue: someOtherValue,
setSomeValue: input => dispatch('something'),
})
return (
<AppContext.Provider value={context}>
{props.children}
</AppContext.Provider>
);
}
function App(props) {
...
return(
<AppContext>
...
</AppContext>
)
}
This way they will only re-render when those specific dependencies update with new values
const MyComponent = React.memo(({
somePropFromContext,
setSomePropFromContext,
otherPropFromContext,
someRegularPropNotFromContext,
}) => {
... // regular component logic
return(
... // regular component return
)
});
function select(){
const { someValue, otherValue, setSomeValue } = useContext(AppContext);
return {
somePropFromContext: someValue,
setSomePropFromContext: setSomeValue,
otherPropFromContext: otherValue,
}
}
function connectToContext(WrappedComponent, select){
return function(props){
const selectors = select();
return <WrappedComponent {...selectors} {...props}/>
}
}
import connectToContext from ...
import AppContext from ...
const MyComponent = React.memo(...
...
)
function select(){
...
}
export default connectToContext(MyComponent, select)
<MyComponent someRegularPropNotFromContext={something} />
//inside MyComponent:
...
<button onClick={input => setSomeValueFromContext(input)}>...
...
MyComponent
will re-render only if the specifics props from context updates with a new value, else it will stay there.
The code inside select
will run every time any value from context updates, but it does nothing and is cheap.
I suggest check this out Preventing rerenders with React.memo and useContext hook.