Search code examples
reactjsreact-reduxformik

How to reset to initial state upon clicking windows back button or changing route?


features/productSlice.js

export const resetState = createAction("Reset_all")

const initialState = {
    products: [],
    product: {},
    productImages: [], 
    isError: false,
    isLoading: false,
    isLoadingPhoto: false,
    isSuccess: false,
    message: "",
}

export const productSlice = createSlice({
    name: "product",
    initialState,
    reducers: {},
    extraReducers: (builder) => {
      builder
      .addCase(getProducts.pending, (state) => {
          state.isLoading = true;
      })
      .addCase(getProducts.fulfilled, (state, action) => {
          state.isLoading = false;
          state.isError = false;
          state.isSuccess = true;
          state.products = action.payload;
      })
      .addCase(getProducts.rejected, (state, action) => {
          state.isLoading = false;
          state.isError = true;
          state.isSuccess = false;
          state.message = action.error;
      })
      .addCase(getAProduct.pending, (state) => {
          state.isLoading = true;
      })
      .addCase(getAProduct.fulfilled, (state, action) => {
          state.isLoading = false;
          state.isError = false;
          state.isSuccess = true;
          state.product['name'] = action.payload.title
          state.product['description'] = action.payload.description
          state.product['price'] = action.payload.price
          state.product['brand'] = action.payload.brand
          state.product['category'] = action.payload.category
          state.product['tags'] = action.payload.tags
          state.product['colors'] = action.payload.color
          state.product['quantity'] = action.payload.quantity
            // state.product['images'] = action.payload.images  
          state.productImages = action.payload.images  
      })
      .addCase(getAProduct.rejected, (state, action) => {
          state.isLoading = false;
          state.isError = true;
          state.isSuccess = false;
          state.message = action.error;
      })
      .addCase(resetState, () => initialState)
    }
})

export default productSlice.reducer

pages/ProductList.jsx

useEffect(() => {
    dispatch(getProducts())
}, [])

const productState = useSelector((state) => state.product?.products) 

const data1 = [];
for (let i = 0; i < productState.length; i++) {
     data1.push({
         key: i + 1,
         title: productState[i].title,
         image: (
             <img style={{objectFit: "cover"}} src={productState[i].images[0].url} width={50} height={50} />
         ),
         brand: productState[i].brand,
         category: productState[i].category,
         color: productState[i].color,
         quantity: productState[i].quantity,
         price: `${productState[i].price}`,
         action: (
                <div className='d-flex align-items-center'>
                    <Link
                        to={`/admin/product/${productState[i]._id}`}
                        className=" fs-3 text-success"
                    > <-- Link redirecting to update product with formik 
                        <BiEdit />
                    </Link>
                    <button
                        className="ms-3 fs-3 text-danger bg-transparent border-0"
                        // onClick={() => showModal(productState[i]._id)}
                    >
                        <AiFillDelete />
                    </button>
                </div>
          )
    });
}

pages/AddProductForm.jsx

const newProduct = useSelector((state) => state.product) 
    
const { isSuccess, isError, isLoading, isLoadingPhoto, createdProduct, product, productImages } = newProduct

const formik = useFormik({ 
    initialValues: {
        title: product.name || "",
        description: product.description || "",
        price: product.price || "",
        brand: product.brand || "",
        category: product.category || "",
        quantity: product.quantity || "",
        color: selectedColors ? selectedColors : [],
        images: productImages ? productImages : []
    },
    validationSchema: schema,
    onSubmit: (values) => {
        console.log(values) 
        
    }
}) 

useEffect(() => {
    if(id !== undefined){ 
        formik.resetForm() 
        dispatch(resetState()) <-- I tried to reset to initial state and reset the formik form before reading the corresponding data
        dispatch(getAProduct(id))
    } else{
        dispatch(resetState())
    }
}, [id]) 

return (  
    <div className="col-10">
        <CustomInput 
          type="text"
          label="Enter product title"
          name="title"
          onChange={formik.handleChange("title")}
          onBlur={formik.handleBlur("title")}
          val={formik.values.title} 
        />
    </div>

I have an issue that I would like to read the existing data when accessing the page for AddProduct dispatching getAProduct(id) but if I clicked the windows back button or change another route the data could not be reset. Also, the data could not be read correctly while clicking another data from the table in ProductList that it still displaying the previous values in formik until I refresh the page. Are there any solutions to fix this bug?

I have been trying to reset the redux state in different ways but no one works even if I console.log the values they are showing correctly but not displaying correctly in formik


Solution

  • Try with the clean-up function. Like

      useEffect(() => {
        if(id !== undefined){ 
            dispatch(getAProduct(id))
        }
        return()=>{
            formik.resetForm() 
            dispatch(resetState()) <-- I tried to reset to initial state and reset the formik form before reading the corresponding data
        }
    }, [id]) 
    

    This will clear the form and state when you change the route or close the form component