Reputation: 91
I'm using react-redux to create a simple CRUD app. The ability to import titles and descriptions from the input, store them in the array, and delete them has been implemented, but the ability to modify them is difficult and asks for help.
action.js
export const addPosting = (title, description) => {
return {
type: ADD_POSTING,
post: {
id: nextId++,
title,
description
}
};
}
export const updatePosting = (payload) => {
return {
type: UPDATE_POSTING,
payload
}
}
export const deletePosting = (id) => {
return {
type: DELETE_POSTING,
id
}
}
postReducer.js
const initialState = [{
id: 1,
title: ' This is First Post',
description: 'Lorem ipsum dolor sit amet consectetur, adipisicing elit.',
}]
const posts = (state = initialState, action) => {
switch (action.type) {
case ADD_POSTING:
return state.concat(action.post);
case DELETE_POSTING:
return state.filter(post => post.id !== action.id);
case UPDATE_POSTING:
return // help
default:
return state;
}
};
The method that I tried was not modified.
case UPDATE_POSTING:
return state.map(post => post.id === action.id ? {
...action.post,
} :
post
)
form.jsx
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { updatePosting } from '../store/actions';
const Modal = ({ post, modal, close }) => {
// update redux
const posts = useSelector(state => state.posts);
const dispatch = useDispatch();
const onUpdate = (title, description) =>
dispatch(updatePosting(title, description));
// inputs
const [inputs, setInputs] = useState({
title: post.title,
description: post.description,
});
const { title, description } = inputs;
const onChange = e => {
const { value, name } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
const onSubmit = e => {
e.preventDefault();
onUpdate(title, description);
setInputs({
title: post.title,
description: post.description,
});
};
return (
<React.Fragment>
{modal ? (
<React.Fragment>
<div className="modal-container">
<form className="modal" onSubmit={onSubmit}>
<div className="title">
<input
className="titleInput"
type="text"
name="title"
required
value={title}
onChange={onChange}
/>
<button onClick={close}>x</button>
</div>
<div className="des">
<textarea
name="description"
className="modal-des"
cols="30"
rows="10"
required
value={description}
onChange={onChange}
></textarea>
</div>
<button onSubmit={onSubmit}>submit</button>
</form>
</div>
</React.Fragment>
) : null}
</React.Fragment>
);
};
export default Modal;
Thank you for your help in solving this problem.
Upvotes: 1
Views: 3429
Reputation: 736
There are couple of error in you code. Your update call does not provide ID for which you are updating: so first pass the ID of the post which you are changing.
const onUpdate = (id, title, description) =>
dispatch(updatePosting(id, title, description));
Then in your reducer :
case UPDATE_POSTING:
// find the id which are trying to update with new title and description
const filtered = state.filter((post) => post.id === action.payload.id);
filtered.title= action.payload.title;
filtered.description= action.payload.description;
return filtered; //according your need post this
Upvotes: 0
Reputation: 169
resp :
case UPDATE_POSTING:
return state.map((post, index) => {
if (post.id === action.payload.id) {
return Object.assign({}, post, {
title: action.payload.title,
description: action.payload.description,
...
})
}
return post
})
in your action :
updatePosting = (post) => ({
type: UPDATE_POSTING,
payload: {
title: post.title,
description: post.description
}
})
Hope it helps !
Upvotes: 0
Reputation: 63589
It sounds like you need do two operations:
1) filter
out all the posts that don't have the updated post's id.
2) Add the new post to the filtered array and return it as new state.
Note that to do this you will need to send the id
as an argument when you call updatePosting
.
case UPDATE_POSTING: {
const filtered = state.filter((post) => post.id !== action.post.id);
return [ ....filtered, action.post ];
}
Upvotes: 1
Reputation: 1570
Your problem come from the way you use the action
object. It containing your post as payload
property as you put it in the action method :
export const updatePosting = (payload) => {
return {
type: UPDATE_POSTING,
payload
}
}
So, your post can be access with action.payload
case UPDATE_POSTING:
return state.map(post => {
if(post.id === action.payload.id){
post = action.payload;
}
}
)
Upvotes: 0