Reputation: 1021
My Source: https://codesandbox.io/s/x91zl9v78p
I try to edit title and content, but first time, content is not modified, only title is modified.
From the second it works well.
Why this error occurs?
reducers.js :
case UPDATE_POST:
return state.map(
post => (post.id === action.id ? Object.assign({}, post, action) : post)
);
And, Is there a way I want to use the spread operator without using object.assign?
Upvotes: 0
Views: 86
Reputation: 793
Because in item.jsx file this.state.title
and this.state.content
are updated only when input get's changed if either of the input is not changed then either of this.state.title or this.state.content
are empty strings. After adding an item to the list this.props.title
and this.props.content
are available but this.state.title
and this.state.content
initially are defined as "" strings in the component. so insted of taking defaultvalue as this.props.tile and this.props.content, on edit set this.state.title = this.props.title
and this.state.content = this.props.content
then it will work.
Upvotes: 1
Reputation: 452
This occurs because your Item component's constructs with an empty string, so when you edit the title input the state is updated, and if you do not edit the content input it will remain empty.
components/List/items.jsx
class Item extends Component {
constructor(props) {
super(props);
this.state = {
isEdit: false,
title: this.props.title,
content: this.props.content
};
}
//...
}
And to avoid Object.assign
reducers/post.jsx
case UPDATE_POST:
return state.map(
post => (post.id === action.id ? { ...post, ...action } : post)
);
This will clone post
props, and merge action
props.
https://codesandbox.io/s/5xpnm9yrrx
Upvotes: 2
Reputation: 45106
Since you are storing initial values for title and content in props you need to sync initical Item
component state values to props by implementing
static getDerivedStateFromProps({ title, content }) {
return {
title, content
}
}
Otherwise, if user doesn't touch a field (say for content) the code will use default state value which is an empty string.
And, Is there a way I want to use the spread operator without using object.assign?
case UPDATE_POST:
return state.map(
post => (post.id === action.id ? {...post, ...action} : post)
);
Also by spreading entire action into the post you are polluting post object with additional attribute type
. Consider using payload
object instead to pass updated post.
export function updatePost(id, title, content) {
return {
type: UPDATE_POST,
payload: {
id,
title,
content
}
};
}
and then spread the payload
case UPDATE_POST:
return state.map(
post => (post.id === action.payload.id ? {...post, ...action.payload} : post)
);
Upvotes: 1
Reputation: 1279
maybe by using it in the function args like this :
export default function Post(state = initialState, {type, ...post}) {
switch (type) {
case ADD_POST:
return [ ...state, post ];
case REMOVE_POST:
return state.filter(({ id }) => id !== post.id);
case UPDATE_POST:
return state.map( p => (p.id === post.id ? post : p) );
default:
return state;
}
}
Upvotes: 0