Zustand initialize state with a hook

448 views Asked by At

Actually I am working on a project in React JS, with Mantine (V5) for a lot of UI component and hooks. We manage forms with Mantine too, and I have one partucillary form that I need to store in a Zustand state. Problem is to declare and initalize and configure this form, we have to call a hook (useForm())

So when I save first time, with the rerender, it works, but when I refresh, and that sounds logic, everything is broken and I have a white screen with these errors :

bundle.js:541680 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
bundle.js:543049 Uncaught TypeError: Cannot read properties of null (reading 'useState')
    at useState (bundle.js:543049:25)
    at useForm (bundle.js:68359:80)
    at bundle.js:19188:65
    at createStoreImpl (bundle.js:561972:11)
    at createStore (bundle.js:561976:50)
    at createImpl (bundle.js:561903:111)
    at create (bundle.js:561911:45)
    at ./src/components/panier/CartForm.ts (bundle.js:19184:76)
    at options.factory (bundle.js:562575:31)
    at __webpack_require__ (bundle.js:562015:33)

I searched, but not if that's possible and how configure with my obligations, but I found nothing, and things that surprise me, is that it's possible to call another Zustand's store with its own hook in the initialization. I needed that too and it does not seem to be a problem.

Anyway, that's my store :

CartStore.ts

import { UseFormReturnType, useForm } from "@mantine/form";
import { getRegistredAddresses } from "components/catalogues/apiActions";
import { create } from "zustand";

enum AddressMode {
    NEW_ADDRESS= "new_address",
    SELECTED_ADDRESS= "selected_address"
}

interface CartState {
    addressMode:AddressMode;
    opened: boolean;
    registeredAddresses: RegisteredAdresses[];
    availableModes: AvailableModes[];
    form: UseFormReturnType<CartFormValues, (values: CartFormValues) => CartFormValues>
}

type CartFunctions = {
    setAddressMode: (addressMode: AddressMode) => void;
    setOpened: (opened: boolean) => void;
    setRegistredAddresses: (registredAddresses: RegisteredAdresses[]) => void;
    getRegistredAddresses: () => void;
    setAvailableModes: (availableModes: AvailableModes[]) => void;
}

type CartStore = CartState & CartFunctions


export const useCartStore = create<CartStore>((set, get) => ({
    addressMode: AddressMode.SELECTED_ADDRESS,
    setAddressMode: (addressMode: AddressMode) => set({ addressMode: addressMode }),

    opened: false,
    setOpened: (opened: boolean) => set({ opened: opened }),

    registeredAddresses:[
        {
            value: '',
            label: ''
        }
    ],
    setRegistredAddresses: (registredAddresses: RegisteredAdresses[]) => set({ registeredAddresses: registredAddresses }),
    getRegistredAddresses:  async() => {
        const addresses = await getRegistredAddresses();
        set({ registeredAddresses: addresses })
    },

    availableModes:[
        {
            value: '',
            label: ''
        }
    ],
    setAvailableModes: (availableModes: AvailableModes[]) => set({ availableModes: availableModes}),

    form: useForm<CartFormValues>({
        initialValues: {
            deliveryContactInfos: {
                lastName: '',
                firstName: '',
                email: '',
                phoneNumber: '',
                socialReason : ''
            },
            address: {
                code: '',
                city: '',
                street: '',
                state: '',
                country: '',
                zipCode: ''
            },
            selectedAddress: null,
            expectedDeliveryDate: '',
            paymentMode: ''
        },
        validate: {
            deliveryContactInfos: {
                lastName: (value: string) => value.length === 0 ? "Veuillez renseigner un nom" : null,
                firstName: (value: string) => value.length === 0 ? "Veuillez renseigner un prénom" : null,
                phoneNumber: (value: string) => {
                    if (value.length > 0) {
                        const regex = new RegExp(/^((\+)33|0)[1-9](\d{2}){4}$/);
                        const test = regex.test(value);
                        return (
                            test ? null : 'Le numéro de téléphone n\'est pas valide'
                        )
                    }
                },
                email: (value: string) => {
                    if (value.length > 0) {
                        const regex = new RegExp(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/);
                        const testEmail = regex.test(value);
                        return (
                            testEmail ? null : 'L\'adresse email n\'est pas valide'
                        )
                    }
                },
            },
            address: {
                city: (value: string) => (get().addressMode === AddressMode.NEW_ADDRESS && value.length === 0) && "Veuillez renseigner une ville",
                street: (value: string) => (get().addressMode === AddressMode.NEW_ADDRESS && value.length === 0) && "Veuillez renseigner une rue",
                country: (value: string) => (get().addressMode === AddressMode.NEW_ADDRESS && value.length === 0) && "Veuillez renseigner un pays",
                zipCode: (value: string) =>
                    get().addressMode === AddressMode.NEW_ADDRESS && (value.length === 0
                        ? "Veuillez renseigner un code postal"
                        : !(/[0-9]{5}/).test(value)
                            ? "Le format du code postal est incorrect"
                            : value.length > 5
                                ? "Le code postal doit contenir 5 caractères"
                                : null),
    
            },
            selectedAddress: (value: string|null) => (get().addressMode === AddressMode.SELECTED_ADDRESS && value === null) && "Veuillez renseigner une adresse de livraison", 
            paymentMode: (value: string) => value.length === 0 && "Veuillez renseigner un mode de paiement",
            expectedDeliveryDate: (value: string) => value.length === 0 && "Veuillez renseigner une date de livraison",
        }
    })
}))

0

There are 0 answers