Reputation: 1
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
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
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