Constantine Solovei
Constantine Solovei

Reputation: 1

React + Redux does not update store

I'm doing telephone list using React and Redux, and have the issue. What should be expected: user puts his data in modal form and when he clicks Submit button - onClick function triggers and data dispatches to the Redux store, and after from store it goes to the localStorage, where all the data will be stored.

The issue: instead of creating an array with object containing data in store, the empty array has been created. After next click on Submit button - data from the first click puts instead of empty array. And so going on.

Had same issue with plain React setState.

The code:

App:

import React from "react";
import { Input } from "../components/Input";
import { Table } from "../components/Table";
import { ButtonAdd } from "../components/ButtonAdd";
import { connect } from "react-redux";
import { setInput, setUser, setFormModalStatus, setSuccessModalStatus} from 
"../actions/dataActions";

class App extends React.Component {

constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.openFormModal = this.openFormModal.bind(this);
    this.closeFormModal = this.closeFormModal.bind(this);
    this.openSuccessModal = this.openSuccessModal.bind(this);
    this.closeSuccessModal = this.closeSuccessModal.bind(this);
}

openFormModal() {
    this.props.setFormModalStatus(true);
}

closeFormModal() {
    this.props.setFormModalStatus(false);
}

openSuccessModal() {
    this.props.setSuccessModalStatus(true);
}

closeSuccessModal() {
    this.props.setSuccessModalStatus(false);
}

handleSubmit(e) {
    this.closeFormModal();
    this.openSuccessModal(); //this is for modals

    const datas = this.props.form.input.values //{name: 'Rick', tel: 12345}
    this.props.setUser(datas); //making dispatch with data

    console.log(this.props.data.users); // [] - the issue

    const testData = {name: Josh, tel: 54321};
    this.props.setUser(testData);

    console.log(this.props.data.users); //[{name: 'Rick, tel: 12345}]

    e.preventDefault();
    this.props.form.input.values = '';
}
render() {
    return (
        <div className="container">
            <div className="row">
                <div className="col-xs-12 col-md-10 col-md-offset-1">
                    <div className="box">
                        <Input input={this.props.input}/>
                        <ButtonAdd 
                            formModalStatus=
{this.props.data.formModalStatus}
                            successModalStatus=
{this.props.data.successModalStatus}
                            openFormModal={this.openFormModal}
                            closeFormModal={this.closeFormModal}
                            closeSuccessModal={this.closeSuccessModal}
                            handleSubmit={this.handleSubmit}
                        />
                    </div>
                    <Table />
                </div>
            </div>
         </div>
        );
    }
}

const mapStateToProps = (state) => {
    return {
        data: state.data,
        form: state.form
    };
  };

const mapDispatchToProps = (dispatch) => {
    return {
        setInput: (input) => {
            dispatch(setInput(input));
        },
        setUser: (user) => {
            dispatch(setUser(user));
        },
        setFormModalStatus: (boolean) => {
            dispatch(setFormModalStatus(boolean));
        },
        setSuccessModalStatus: (boolean) => {
            dispatch(setSuccessModalStatus(boolean));
        }
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

Reducer:

const dataReducer = (state = {
    input: "",
    users: [],
    formModalStatus: false,
    successModalStatus: false
}, action) => {
    switch (action.type) {
        case "SET_INPUT":
            state = {
                ...state,
                input: action.payload
            };
            break;
        case "SET_USER":
             state = {
                ...state,
                users: [...state.users, action.payload]
            };
            break;
        case "SET_FORM_MODAL_STATUS":
            state = {
                ...state,
                formModalStatus: action.payload
            }
        case "SET_SUCCESS_MODAL_STATUS":
            state = {
                ...state,
                successModalStatus: action.payload
            }
    }
    return state;
};

export default dataReducer;

Appropriane action:

export function setUser(user) {
    return {
        type: "SET_USER",
        payload: user
    };
}

Upvotes: 0

Views: 1431

Answers (2)

Jenna Rajani
Jenna Rajani

Reputation: 243

You should never mutate state directly in React or Redux. With Redux you want to always return a new object to replace the previous state.

Maybe try something like this instead?

switch (action.type) {
    case 'SET_INPUT':
        return {
            ...state,
            input: action.payload
        };
    case 'SET_USER':
        return {
            ...state,
            users: [...state.users, action.payload]
        };
    case 'SET_FORM_MODAL_STATUS':
        return {
            ...state,
            formModalStatus: action.payload
        };
    case 'SET_SUCCESS_MODAL_STATUS':
        return {
            ...state,
            successModalStatus: action.payload
        };
    default:
        return state;
}

Upvotes: 0

nikjohn
nikjohn

Reputation: 21832

If you could provide a working sample on WebpackBin or something, that would help debug the issue better.

From my experience, this normally happens when the state is mutated. Could you try using the following format on your reducer:

state = {
            state.set('users', [...state.users, action.payload])
        };

The existing functionality is mutating the existing state at state=...

state = {
            ...state,
            users: [...state.users, action.payload]
        };

PS: Also, you're missing break statements in your last two action cases in your reducer. And your default case

Upvotes: 1

Related Questions