简体   繁体   中英

How to migrate app state from React Context to Redux Tool Kit?

What I'm trying to achieve:

I have a NextJS + Shopify storefront API application. Initially I set up a Context api for the state management but it's not that efficient because it re-renders everything what's wrapped in it. Thus, I'm moving all state to the Redux Toolkit.

Redux logic is pretty complex and I don't know all the pitfalls yet. But so far I encounter couple problems. For example in my old Context API structure I have couple functions that take a couple arguments :

    const removeFromCheckout = async (checkoutId, lineItemIdsToRemove) => {
        client.checkout.removeLineItems(checkoutId, lineItemIdsToRemove).then((checkout) => {
            setCheckout(checkout);
            localStorage.setItem('checkout', checkoutId);
        });
    }

    const updateLineItem = async (item, quantity) => {
        const checkoutId = checkout.id;
        const lineItemsToUpdate = [
            {id: item.id, quantity: parseInt(quantity, 10)}
        ];
        client.checkout.updateLineItems(checkoutId, lineItemsToUpdate).then((checkout) => {
            setCheckout(checkout);
        });
    }

One argument ( checkoutId ) from the state and another one ( lineItemIdsToRemove ) extracted through the map() method. Inside actual component in JSX it looks and evokes like this:

<motion.button 
    className="underline cursor-pointer font-extralight"
    onClick={() => {removeFromCheckout(checkout.id, item.id)}}
>

How can I declare this type of functions inside createSlice({ }) ? Because the only type of arguments reducers inside createSlice can take are (state, action) . And also is it possible to have several useSelector() calls inside one file?

I have two different 'Slice' files imported to the component:

    const {toggle} = useSelector((state) => state.toggle);
    const {checkout} = useSelector((state) => state.checkout);

and only the {checkout} gives me this error: TypeError: Cannot destructure property 'checkout' of 'Object(...)(...)' as it is undefined.

Thank you for you're attention, hope someone can shad the light on this one.

You can use the prepare notation for that:

const todosSlice = createSlice({
  name: 'todos',
  initialState: [] as Item[],
  reducers: {
    addTodo: {
      reducer: (state, action: PayloadAction<Item>) => {
        state.push(action.payload)
      },
      prepare: (id: number, text: string) => {
        return { payload: { id, text } }
      },
    },
  },
})

dispatch(todosSlice.actions.addTodo(5, "test"))

But 99% of the cases you would probably stay with the one-parameter notation and just pass an object as payload, like

dispatch(todosSlice.actions.addTodo({ id: 5, text: "test"}))

as that just works out of the box without the prepare notation and makes your code more readable anyways.

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