My store and reducers When I combine two reducers in the store, my maps with lists stop working in the project and show an error. Error - Uncaught TypeError: tovars.map is not a function
import { configureStore } from "@reduxjs/toolkit";
import ordersReducer from "../components/content/tovars/tovarsSlice";
import loginReducer from "../components/content/login/loginSlice";
const stringMiddleware = () => (next) => (action) => {
if (typeof action === 'string') {
return next({
type: action
})
}
return next(action)
};
const store = configureStore({
reducer: {
tovars: ordersReducer,
login: loginReducer
},
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(stringMiddleware),
devTools: process.env.NODE_ENV !== 'production',
})
export default store;
I tried to do const tovars = useSelector((state) => state.tovarsList);, but it doesn't work
But when I leave only one reducer in the store, everything works.
My component After connecting the second reducer, an error occurs on all map functions in the project.
const Tovars = () => {
const dispatch = useDispatch();
const tovars = useSelector(tovarsList);
const showBasket = useSelector((state) => state.showBasket);
const displayedTovars = useSelector((state) => state.displayedTovars)
const { loadingTovar, errorLoading } = useLoadingStatus();
const listRef = useRef(null);
useEffect(() => {
dispatch(fetchTovars());
},[dispatch])
useEffect(() => {
listRef.current?.scrollIntoView()
}, [tovars,displayedTovars]);
const renderTovars = useMemo(() =>{
const list = tovars.map((item,id) => (
<li key={item.id}>
<div className="content_card">
<p className="title_card">{item.title}</p>
<p className="category_card">{item.category}</p>
<NavLink to="/InfoCard" className="nav-link">
<img src={item.image}
alt="card"
onClick={() => dispatch(selectCard(item,item.id))} />
</NavLink>
<div className="price_rating_card">
<p className="price_card">Price: {item.price} $</p>
</div>
<div className="del_card">X</div>
<button className="card_buy"
onClick={() => dispatch(addTovar(item))
}
>Buy</button>
</div>
</li>
)).slice(0, displayedTovars)
return <ul className="list">{list}
<div ref={listRef}></div>
</ul>
},[dispatch, tovars, displayedTovars])
const nextClickTovars = useCallback(() => {
dispatch(nextDisplayedTovars(displayedTovars + 6))
},[dispatch, displayedTovars])
const backClickTovars = useCallback(() => {
if(displayedTovars <= 6){
return false;
}
dispatch(backDisplayedTovars(displayedTovars - 6))
},[dispatch, displayedTovars])
return(<div className="content">
<div className="filter">
<Filter />
<ShowDiscounts />
</div>
<div className="spinner_tovars">
{loadingTovar}
{errorLoading}
</div>
<div className="content_tovars_pagination" >
<Pagination nextTovars={nextClickTovars}
backTovars={backClickTovars}
/>
{renderTovars}
<Pagination nextTovars={nextClickTovars}
backTovars={backClickTovars}
/>
</div>
{showBasket && <BasketModal />}
</div>)
}
export default Tovars;
When the reducer functions are passed to the reducer
property of the store configuration, the state is tovars
, e.g. state.tovars
.
reducer: {
tovars: ordersReducer,
login: loginReducer
},
In the component ensure you are selecting the correct state.
Example:
const tovars = useSelector(state => state.tovars);
Or ensure that the tovarsList
selector function is correctly accessing and selecting the correct state.
Example:
const tovarsList = state => state.tovars;
const tovars = useSelector(tovarsList);
Ensure that all dispatched action that update the state.tovars
state maintains the correct state invariant. Based on the usage it appears that state.tovars
is an array. Make sure the local tovars
variable of the selected state is an array value such that tovars.map
is a function that is callable when rendering. If this isn't possible to maintain the state invariant then at least refactor the selector function to guarantee a returned array if state.tovars
is falsey.
Example:
const tovarsList = state => state.tovars || [];
const tovars = useSelector(tovarsList);