Bryce Stampfl
Bryce Stampfl

Reputation: 72

React Redux - app/store resets after added item to store

I cant figure out why when I add an item to my store the app resets. I can see for a split second that its being added to my list but then I can see all my component flicker and reload. Inspecting the console doesn't bring up any warnings.

I also plugged in just my addProduct component and productsSlice into the redux template and it also reloaded the app.

Basic HTML for adding a product with hooks:

import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { addProduct } from '../_reducers/productsSlice'

const AddProduct = () => {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('')
    const [price, setPrice] = useState('')

    const onTitleChanged = e => setTitle(e.target.value);
    const onDescriptionChanged = e => setDescription(e.target.value);
    const onPriceChanged = e => setPrice(e.target.value);

    const dispatch = useDispatch();


    return (
        <section>
            <h2>Add a new Product</h2>
            <form>
                <label htmlFor="Title">Title</label>
                <input
                    type="text"
                    name="title"
                    value={title}
                    onChange={onTitleChanged} />

                <label htmlFor="Price">Price</label>
                <input
                    type="text"
                    value={price}
                    onChange={onPriceChanged} />

                <label htmlFor="Description">Description</label>
                <textarea
                    value={description}
                    onChange={onDescriptionChanged} />

                <button onClick={() => dispatch(addProduct({
                    title: title,
                    price: price,
                    description: description
                }))}>
                    Submit
                </button>
            </form>
        </section>
    )
}

export default AddProduct;

My Reducer:

import { createSlice } from '@reduxjs/toolkit'

const initialProductsState = [
    // { name: '1', price: 10, description: 'testDescrip1' },
    // { name: '2', price: 20, description: 'testDescrip2' },
    // { name: '3', price: 30, description: 'testDescrip3' },
    { name: '4', price: 40, description: 'testDescrip4' }]



export const productsSlice = createSlice({
    name: 'products',
    initialState: initialProductsState,
    reducers: {
        addProduct: (state, action) => {
            state.push(action.payload)
        },
    }
})

export const { addProduct } = productsSlice.actions;


export default productsSlice.reducer

Listing of the products:

import React from 'react';
import { useSelector } from 'react-redux'
import { Row, Col } from 'react-bootstrap'
import ProductItem from "./ProductItem"


const ProductList = () => {

    const products = useSelector(state => state.products)
    let numberRendered = 3;

    const renderedProducts = products.map(item => (
            <ProductItem product={item} />
    ))

    return (
        <div id="ProductList">
            <Row>
                <Col>
                    {renderedProducts}
                </Col>
            </Row>
        </div>
    )
}

export default ProductList;

And the product component styled with react-bootstrap:

import React from 'react';
import {productSlice} from '../_reducers/productsSlice';
import { Card, Col, Row } from 'react-bootstrap'

const ProductItem = (props) => {


    return (
        <Card>
            <Card.Body>
                <Row>
                    <Col md={4}>
                        <Card.Img variant="float" src={process.env.PUBLIC_URL + 'placeholder.png'} />

                    </Col>
                    <Col md={8}>
                        <Card.Title>{props.product.title}</Card.Title>

                        <Card.Text>{props.product.description}</Card.Text>
                        <Card.Subtitle>{props.product.price}</Card.Subtitle>
                    </Col>
                </Row>



            </Card.Body>
        </Card>
    )
}

export default ProductItem;

store:

import { configureStore } from '@reduxjs/toolkit'
import productsSlice from '../src/_reducers/productsSlice'

const store = configureStore({
    reducer: {
        products: productsSlice,
    }
})

export default store;

Upvotes: 0

Views: 47

Answers (1)

Dakota Lee Martinez
Dakota Lee Martinez

Reputation: 621

Pretty sure you just need to add an event.preventDefault() to the form's submit event

import React, { useState } from 'react'
import { useDispatch } from 'react-redux'
import { addProduct } from '../_reducers/productsSlice'

const AddProduct = () => {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('')
    const [price, setPrice] = useState('')

    const onTitleChanged = e => setTitle(e.target.value);
    const onDescriptionChanged = e => setDescription(e.target.value);
    const onPriceChanged = e => setPrice(e.target.value);

    const dispatch = useDispatch();


    const handleSubmit = (e) => {
      e.preventDefault();
      dispatch(addProduct({
        title: title,
        price: price,
        description: description
      }))
    }
    return (
        <section>
            <h2>Add a new Product</h2>
            <form onSubmit={handleSubmit}>
                <label htmlFor="Title">Title</label>
                <input
                    type="text"
                    name="title"
                    value={title}
                    onChange={onTitleChanged} />

                <label htmlFor="Price">Price</label>
                <input
                    type="text"
                    value={price}
                    onChange={onPriceChanged} />

                <label htmlFor="Description">Description</label>
                <textarea
                    value={description}
                    onChange={onDescriptionChanged} />

                <button type="submit">
                    Submit
                </button>
            </form>
        </section>
    )
}

export default AddProduct;

Without the preventDefault submitting the form will submit a get request to the same route, which will cause the component to reload.

Upvotes: 1

Related Questions