简体   繁体   中英

Redux combineReducer and createStore, how to pass initial state

Problem:

Error: No Matching "@@redux/INITj.pbvmc" - action type

The first stack frame references the first imported reducer, cart_reducer , 2 frames further is combineReducers

I believe this error is related to Redux failing to get initial state.

What I'm trying to do:

Convert an ecommerce page from useReducer / contextAPI to Redux. There are 3 reducers each with their own initial state. I am trying to combine these reducers and pass them into createStore() . I believe my current setup is mostly correct, I just cant figure out how to pass the [preloadedState] into the createStore()

From the Redux docs . I think the answer is here but I am having trouble understanding the statement.

If you produced reducer with combineReducers, this must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your reducer can understand.

import { combineReducers, createStore } from 'redux';
import cart_reducer from './cart_reducer';
import products_reducer from './products_reducer';
import filter_reducer from './filter_reducer';

const root_reducer = combineReducers({
  cartReducer: cart_reducer,
  productsReducer: products_reducer,
  filterReducer: filter_reducer,
});

const store= createStore(
  root_reducer,
  // pass initial states here... but how?
  );

state is then passed to the Provider

import store from './reducers/root_reducer';

function App() {
  return (
    <Provider store={store}> // here
      <AuthWrapper>
        <Router>
          <Navbar />
          <Sidebar />
          <Switch>
            <Route exact path='/'>
              <Home />
            </Route>
            <Route exact path='/about'>
              <About />
            </Route>
            <Route exact path='/cart'>
              <Cart />
            </Route>
            <Route exact path='/products'>
              <Products />
            </Route>
            <Route exact path='/products/:id'>
              <SingleProduct />
            </Route>
            <PrivateRoute exact path='/checkout'>
              <Checkout />
            </PrivateRoute>
            <Route exact path='*'>
              <Error />
            </Route>
          </Switch>
          <Footer />
        </Router>
      </AuthWrapper>
    </Provider>
  );
}

Here is one of my reducers:

import {
  ADD_TO_CART,
  CLEAR_CART,
  COUNT_CART_TOTALS,
  REMOVE_CART_ITEM,
  TOGGLE_CART_ITEM_AMOUNT,
} from '../actions';

const initialState = {
  cart: [],
  // cart: getLocalStorage(),
  total_items: 0,
  total_amount: 0,
  shipping_fee: 534,
};

function cart_reducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TO_CART: {
      const { id, color, amount, product } = action.payload;
      const tempItem = state.cart.find((i) => i.id === id + color);
      if (tempItem) {
        const tempCart = state.cart.map((cartItem) => {
          if (cartItem.id === id + color) {
            let newAmount = cartItem.amount + amount;
            if (newAmount > cartItem.max) {
              newAmount = cartItem.max;
...ect
...ect

export default cart_reducer;

For saksh73

In a component

<button
        type='button'
        className='remove-btn'
        onClick={() => dispatch(removeItem(id))}
      >

In actions.js

const REMOVE_CART_ITEM = 'REMOVE_CART_ITEM';

export const removeItem = (id) => {
  return { type: REMOVE_CART_ITEM, payload: id };
};

In cart_reducer

case REMOVE_CART_ITEM: {
      const newCart = state.cart.filter((item) => item.id !== action.payload);
      return {
        ...state,
        cart: [...newCart],
      };
    }

Your setup is correct. For the initial state you can have the initial state of each reducer in their respective initial state.

Your action must return an object if you are not using any middleware. If you want to use any middleware ie redux thunk, redux saga then you must pass the second argument in createStore .

Here is an example:

import { createStore, applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk";
import { combineReducers } from "redux";

import signUp from "./signUp";
import login from "./login";
import user from "./user";

const rootReducer = combineReducers({
  signUp,
  login,
  user,
});

const store = createStore(rootReducer, applyMiddleware(thunk, logger));

export default store;

action example:

export function logIn(email, password) {
        dispatch({
          type: "LOGIN_SUCCESS",
          payload: {
            email: email,
            password: password
          }
        });
  };

The doc just mean you need to pass initial state for each child reducer with the same key accordingly.

const store= createStore(
  root_reducer,
  // pass initial states with the same key 
  {
    cartReducer: cart_reducer_state,
    productsReducer: products_reducer_state,
    filterReducer: filter_reducer_state
  }
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM