I'm trying to pass an element as my initial state. like this:
import { createSlice } from "@reduxjs/toolkit";
import { Home } from "@mui/icons-material";
export const setIconSlice = createSlice({
name: "IconSet",
initialState: {
icon: <Home />,
},
reducers: {
setIcon: (state, action) => {
state.icon = action.payload;
},
},
});
export const { setIcon } = setIconSlice.actions;
export default setIconSlice.reducer;
I want to have home icon of material UI as my initial state but as you can guess I get
A non-serializable value was detected in the state
I tried to disable serializable check from store middleware. Error goes away but I still can't see any icon.
is there anyway to pass an element as a state? I don't get any error with useState but I want it globally in my entire app so I don't want to pass it from element to element with useState
Well yes, redux forces you to use serializable —like plain object— elements in the state.
I was thinking on making use of a value —enums— that would let you import previously imported elements with lazy.
initialState: {
// icon values will be strings
icon: 'home',
},
And in your component try this:
// lazy import the components for code-splitting
const HomeIcon = React.lazy(() => import('./Home'));
const SearchIcon = React.lazy(() => import('./Search'));
// get the current icon from the state
const icon = useSelector(state => state.icon);
// helper
const getStateIcon = () => {
// return lazy loaded element depending of the icon string value
switch (icon) {
case 'home':
return <HomeIcon />;
case 'search':
return <SearchIcon />;
default:
return <HomeIcon />;
}
}
// in your jsx file
<React.Suspense fallback={<div>Loading...</div>}>
{getStateIcon()}
</React.Suspense>
This way you will have the option for code-splitting and make your loading time lighter.
Check how how lazy works in this sandbox
You can use a string to save icon
initialState:{ icon: 'home'}
In App.js (or any component you need to use icon)
const icon = useSelector(state=>state.icon)
Then, render Home Component conditionally based on icon stored in redux
icon ==='home' && <Home/>
I'd recommend to map the name of the icon to a component instance, redux does not like things it can't serialize for a reason:
// Import all icons you want to make available
import { Home, OtherIcon } from "@mui/icons-material";
// Map their name to component instances
export const icons = {
home: <Home />,
othericon: <OtherIcon />
};
// Now you simply put 'home' (as a string) in redux for the initial state
// When using the icon, retrieve it like this:
const iconPath = useSelector(state => state.iconPath);
const icon = icons[iconPath];