I have been trying to optimise the my react code, my goal is to make sure existing toast components don’t re render when new ones are added. or when I delete one toast, rest of them don’t re render. all toasts live in toast provider.
current behaviour:
whenever I add a new toast, existing ones get re rendered.
whenever I remove a toast, the remaining ones get re rendered again.
Let me show some code first (only relevant part):
ToastProvider.jsx
function ToastProvider({ children }) {
const [toasts, setToasts] = useState([])
const memoisedClearToast = React.useCallback(() => setToasts([]), [])
useKeyDown("Escape", memoisedClearToast)
const addToast = (toast) => {
setToasts([...toasts, toast]);
};
const dismissToast = (toastId) => {
const nextToasts = [...toasts]
const filtered = nextToasts.filter((toast) => toast.id !== toastId)
setToasts(filtered)
}
const value = React.useCallback({ toasts, addToast, dismissToast }, [toasts])
return (
<ToastContext.Provider value={value}>
{children}
</ToastContext.Provider>
)
}
ToastShelf.jsx:
function ToastShelf() {
const {toasts} = useContext(ToastContext)
console.log(`toast shelf render`)
return (
<ol>
{toasts.map((toast) => {
return (
<li key={toast.id}>
<Toast
id={toast.id}
variant={toast.variant}
message={toast.message}
/>
</li>
)
})}
</ol>
);
}
export default React.memo(ToastShelf);
Toast.jsx
function Toast({ id, variant, message }) {
const { dismissToast } = useContext(ToastContext)
console.log(`toast render`)
return (
<div>
<button onClick={() => dismissToast(id)}>
<X size={24} />
</button>
</div>
);
}
export default React.memo(Toast);
All Toasts are getting re rendered whenever I add a toast, looking at the code, only prop that’s changing is coming via context and it’s dismissToast function. How can I make sure, that whenever new Toast is added to the toasts array in context, components depending only on the dismissToast function don’t get a fresh copy of dismissFunction ? The existing toasts don’t need to re render whenever new one is added right?
I haven’t been able to find a way around this. I have tried memoizing the value
prop that is given to the context provider.