React not updating state on reused component? - reactjs

I'm updating a project from a MERN stack course I completed earlier. It has a 'Like' and 'Dislike' button, which update in MongoDB, and then the updated number of likes gets rendered to the screen. Right now, it's updating the database, but not re-rendering the updated information on the screen.
For example, I'll hit the like button on a post (should take it from 2 likes to 3). I can see the updated information in MongoDB (3), but it never adds the like on the screen (2). Additionally, Redux DevTools tells me it didn't update the state automatically (still 2). I then hit the 'refresh' button on my browser, and the updated number of likes is there (3).
I used this component and these actions/reducers in another component, and they work perfectly. For some reason, it's behaving differently here. Maybe something to do with the props I'm passing in? UseEffect issue?
I tried console.logging the likes property (post.likes) before and after the PostLikeAndDislike component, and it's the same number of likes both times (that is, if it's 3 before I click, it's 3 after I click).
PostLikeAndDislike component:
const PostLikeAndDislike = ({
addLike,
removeLike,
deletePost,
auth,
post: { _id, text, name, avatar, user, likes, comments, date },
showActions
}) => (
<div className="post bg-white p-1 my-1">
<div>
{showActions && (
<Fragment>
<button
onClick={e => addLike(_id)}
type="button"
className="btn btn-light"
>
<i className="fas fa-thumbs-up" />{' '}
{likes.length > 0 && <span>{likes.length}</span>}
</button>
<button
onClick={e => removeLike(_id)}
type="button"
className="btn btn-light"
>
<i className="fas fa-thumbs-down" />
</button>
</Fragment>
)}
</div>
</div>
)
PostLikeAndDislike.defaultProps = {
showActions: true
}
const mapStateToProps = state => ({
auth: state.auth
})
export default connect(
mapStateToProps,
{ addLike, removeLike, deletePost }
)(PostLikeAndDislike)
The component PostLikeAndDislike is being imported into:
const Post = ({ getPost, post: { post, loading }, match }) => {
useEffect(
() => {
getPost(match.params.id)
},
[getPost]
)
return loading || post === null ? (
<Spinner />
) : (
<Fragment>
{console.log('Before', post.likes)}
<PostLikeAndDislike post={post} showActions={true} />
<div className="comments">
{post.comments.map(comment => (
<CommentItem key={comment._id} comment={comment} postId={post._id} />
))}
</div>
{console.log('After', post.likes)}
<CommentForm postId={post._id} />
</Fragment>
)
}
const mapStateToProps = state => ({
post: state.post
})
export default connect(
mapStateToProps,
{ getPost, addLike, removeLike }
)(Post)
Actions:
// Get post
export const getPost = id => async dispatch => {
try {
const res = await axios.get(`/api/posts/${id}`)
dispatch({
type: GET_POST,
payload: res.data
})
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
})
}
}
// Add like
export const addLike = id => async dispatch => {
try {
const res = await axios.put(`/api/posts/like/${id}`)
dispatch({
type: UPDATE_LIKES,
payload: { id, likes: res.data }
})
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
})
}
}
// Remove like
export const removeLike = id => async dispatch => {
try {
const res = await axios.put(`/api/posts/unlike/${id}`)
dispatch({
type: UPDATE_LIKES,
payload: { id, likes: res.data }
})
} catch (err) {
dispatch({
type: POST_ERROR,
payload: { msg: err.response.statusText, status: err.response.status },
loading: false
})
}
}
Reducer:
const initialState = {
posts: [],
post: null,
loading: true,
error: {}
}
case GET_POST:
return {
...state,
post: payload,
loading: false
}
case UPDATE_LIKES:
return {
...state,
posts: state.posts.map(
post =>
post._id === payload.id ? { ...post, likes: payload.likes } : post
)
}
Like I said above, I'm expecting the 'like' button and 'dislike' button to change the number of likes and re-render it to the screen immediately.
Thanks in advance!

Related

How to go to detail of the pokemon with poke api in react

I am listing pokemons with this api: https://pokeapi.co/api/v2/pokemon/ so when I click the pokemon I want to go to the page.
So for this in details screen:
const dispatch = useDispatch();
const pokemonId = props.match.params.id;
const pokemonDetails = useSelector((state) => state.pokemonDetails);
const { loading, error, pokemon } = pokemonDetails;
useEffect(() => {
dispatch(detailsPokemon(pokemonId));
}, [dispatch, pokemonId]);
And my action:
export const detailsPokemon = (pokemonId) => async (dispatch) => {
dispatch({ type: POKEMON_DETAILS_REQUEST, payload: pokemonId });
try {
const { data } = await Axios.get(`https://pokeapi.co/api/v2/pokemon/${pokemonId}`);
dispatch({ type: POKEMON_DETAILS_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: POKEMON_DETAILS_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
And my reducer:
export const pokemonDetailsReducer = (
state = { pokemon: {}, loading: true },
action
) => {
switch (action.type) {
case POKEMON_DETAILS_REQUEST:
return { loading: true };
case POKEMON_DETAILS_SUCCESS:
return { loading: false, pokemon: action.payload };
case POKEMON_DETAILS_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
But I am getting pokemon id undefined that's why I cannot go to the page.
export default function Pokemon(props) {
const { pokemon } = props;
return (
<div key={pokemon.id} className="card">
<a href={`/pokemon/${pokemon.id}`}>
<img className="medium" src={pokemon.image} alt={pokemon.name} />
</a>
<div className="card-body">
<a href={`/pokemon/${pokemon.id}`}>
<h2>{pokemon.name}</h2>
</a>
<Rating
rating={pokemon.rating}
numReviews={pokemon.numReviews}
></Rating>
</div>
</div>
);
}

this.props.xxx is not a function

I've found a few other posts with similar errors and I've already ruled out:
The function is correctly imported in curly braces
The action is dispatched
The file path is correct
It must just be some silly mistake but Ive been looking at it for ages and cannot seem to find it, and help appreciated!
action:
export const deleteRow = (rowId) => (dispatch) => {
dispatch({ type: "LOADING_UI" });
axios
.delete(`/row/${rowId}`)
.then((res) => {
dispatch({
type: "DELETE_ROW",
payload: res.data,
});
dispatch(clearErrors());
})
.catch((err) => {
dispatch({
type: "SET_ERRORS",
payload: err.response.data,
});
});
};
component:
export class MyDelete extends Component {
state = {
open: false,
};
handleOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
handleDelete = () => {
this.props.deleteRow(this.props.rowId);
this.setState({ open: false });
};
render() {
return (
<Fragment>
<Button onClick={this.handleOpen}>
<HighlightOffIcon color="primary" />
</Button>
<Dialog
open={this.state.open}
onClose={this.handleClose}
fullWidth
maxWidth="sm"
>
<DialogTitle>Are you sure you want to delete this row ?</DialogTitle>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleDelete} color="secondary">
Delete
</Button>
</DialogActions>
</Dialog>
</Fragment>
);
}
}
MyDelete.propTypes = {
deleteRow: PropTypes.func.isRequired,
rowId: PropTypes.string.isRequired,
};
export default connect(null, { deleteRow })(MyDelete);
You are using connect with object shorthand form, it expects each field to be an action creator, and binds each field to dispatch.
Your function deleteRow is not an action creator, so instead you should not use object shorthand form and directly use dispatch:
export class MyDelete extends Component {
//...
deleteRow = (rowId) => {
this.props.dispatch({ type: "LOADING_UI" });
axios.delete(...)
}
//...
}
export default connect()(MyDelete);
Try using the mapDispatchToProps function approach instead of object shorthand form like so :-
const mapDispatchToProps = (dispatch) =>{
return {
deleteRow:(rowId)=>dispatch(deleteRow(rowId));
}
}
export default connect(null, mapDispatchToProps)(MyDelete);

How to use axios to get api items in redux?

I am learning Redux so this may be a basic question and answer but here we go.
I am trying to fetch a list of items from my backend api (/api/items) and pass them into my ShoppingList.js component so that when the component loads the list of items will be displayed. I think that I have to fetch the data in the action, and then call that action in the useEffect hook in the react component, but I am not too sure as I can't seem to get it to work.
Can anyone help me figure this out?
Redux.js
import { createStore } from 'redux';
import axios from 'axios';
const initialState = {
items: [],
loading: false,
};
export const store = createStore(
reducer,
initialState,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
function reducer(state, action) {
switch (action.type) {
case 'GET_ITEMS':
return {
...state,
items: action.payload,
loading: false,
};
case 'ADD_ITEM':
return {
...state,
items: [...state.items, action.payload],
};
case 'DELETE_ITEM':
return {
...state,
items: state.items.filter(item => item.id !== action.payload),
};
case 'ITEMS_LOADING':
return {
...this.state,
loading: true,
};
default:
return state;
}
}
export const getItemsAction = () => ({
return(dispatch) {
console.log('here');
axios.get('api/items').then(response => {
console.log(response);
dispatch({ type: 'GET_ITEMS', payload: response.data });
});
},
});
export const addItemAction = item => ({
type: 'ADD_ITEM',
payload: item,
});
export const deleteItemAction = item => ({
type: 'DELETE_ITEM',
payload: item,
});
export const setItemsLoading = () => ({
type: 'ITEMS_LOADING',
});
ShoppingList.js
export default function ShoppingList() {
const items = useSelector(state => state.items);
const dispatch = useDispatch();
const addItem = name => dispatch(addItemAction(name));
const deleteItem = id => dispatch(deleteItemAction(id));
useEffect(() => {
//call get items dispatch?
getItemsAction();
});
return (
<div className="container mx-auto">
<button
onClick={() => {
const name = prompt('Enter Item');
if (name) {
// setItems([...items, { id: uuid(), name: name }]);
addItem({
id: uuid(),
name: name,
});
}
}}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mt-4"
>
Add Item
</button>
<ul className="mt-4">
<TransitionGroup className="shopping-list">
{items.map(({ id, name }) => (
<CSSTransition
key={id}
timeout={500}
classNames="fade"
style={{ marginBottom: '0.5rem' }}
>
<li>
{' '}
<button
className="bg-red-500 rounded px-2 mr-2 text-white"
onClick={deleteItem.bind(this, id)}
>
×
</button>
{name}
</li>
</CSSTransition>
))}
</TransitionGroup>
</ul>
</div>
);
}
You are close to where you need to be, the missing piece is that redux is synchronous, so you need to use something like redux-thunk or redux-saga to handle async actions such as network requests.
Once you have setup whatever library you want, you would call it similarly to calling a redux action, from a useEffect like you suggest.
So for example, if you use a thunk:
export const getItemsAction = () => ({
return (dispatch) => {
axios.get('api/items').then(response => {
console.log(response)
dispatch({ type: 'GET_ITEMS_SUCCESS', payload: response.data })
}).catch(err => dispatch({ type: 'GET_ITEMS_ERROR', error: err })
},
})
Then you could call it from your effect:
useEffect(() => {
dispatch(getItemsAction())
}, []);
Make sure you add an empty dependency array if you only want to call it once, otherwise it will get called every time your component refreshes.
Note that the thunk is able to dispatch other redux actions, and I changed a few of your actions types to make it more clear what is going on;
GET_ITEMS_SUCCESS is setting your successful response & GET_ITEMS_ERROR sets any error if there is one.

React redux proper updating record and reflecting changes on the screen

For learning purpose I made this web app where I'm trying to implement crud operations. All works properly except UPDATE, where MongoDB record is updated but changes on the screen are not reflected till the refresh.
I'm still learning therefore not everything is crystal clear, I'm suspecting a problem in a REDUCER... or in the component mapStateToProp object...
What am I doing wrong here?
routes/api
Item.findByIdAndUpdate for sure update's db correctly, but should it also return anything so the reducer/action could react to it?
const express = require("express");
const router = express.Router();
const auth = require("../../middleware/auth");
// Item Model
const Item = require("../../models/stories");
// #route GET api/items
// #desc Get All Items
// #access Public
router.get("/", (req, res) => {
Item.find()
.sort({ date: -1 })
.then(items => res.json(items));
});
// #route PUT api/items
// #desc Update An Item
// #access Private
router.put("/:_id", auth, (req, res) => {
Item.findByIdAndUpdate(
req.params._id,
req.body,
{ new: false, useFindAndModify: false },
() => {}
);
});
module.exports = router;
reducers
import {
GET_STORIES,
ADD_STORY,
DELETE_STORY,
STORIES_LOADING,
UPDATE_STORY
} from "../actions/types";
const initialState = {
stories: [],
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_STORIES:
return {
...state,
stories: action.payload,
loading: false
};
case DELETE_STORY:
return {
...state,
stories: state.stories.filter(story => story._id !== action.payload)
};
case ADD_STORY:
return {
...state,
stories: [action.payload, ...state.stories]
};
case UPDATE_STORY:
return {
...state,
stories: action.payload
};
case STORIES_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
actions
import axios from "axios";
import {
GET_STORIES,
ADD_STORY,
DELETE_STORY,
UPDATE_STORY,
STORIES_LOADING
} from "./types";
import { tokenConfig } from "./authActions";
import { returnErrors } from "./errorActions";
export const getStories = () => dispatch => {
dispatch(setStoriesLoading());
axios
.get("/api/stories")
.then(res =>
dispatch({
type: GET_STORIES,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const addStory = story => (dispatch, getState) => {
axios
.post("/api/stories", story, tokenConfig(getState))
.then(res => {
dispatch({
type: ADD_STORY,
payload: res.data
});
})
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const updateStory = story => (dispatch, getState) => {
axios
.put(`/api/stories/${story.id}`, story, tokenConfig(getState))
.then(res => {
dispatch({
type: UPDATE_STORY,
payload: story
});
})
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const deleteStory = id => (dispatch, getState) => {
axios
.delete(`/api/stories/${id}`, tokenConfig(getState))
.then(res => {
dispatch({
type: DELETE_STORY,
payload: id
});
})
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const setStoriesLoading = () => {
return {
type: STORIES_LOADING
};
};
component
import React, { Component } from "react";
import {
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input
} from "reactstrap";
import { connect } from "react-redux";
import { updateStory } from "../../actions/storyActions";
import PropTypes from "prop-types";
class UpdateStoryModal extends Component {
constructor(props) {
super(props);
}
state = {
id: this.props.idVal,
modal: false,
title: this.props.titleVal,
body: this.props.bodyVal
};
static propTypes = {
isAuthenticated: PropTypes.bool
};
toggle = () => {
this.setState({
modal: !this.state.modal
});
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const obj = {
id: this.props.idVal,
title: this.state.title,
body: this.state.body
};
this.props.updateStory(obj);
this.toggle();
};
render() {
return (
<div>
{this.props.isAuthenticated ? (
<button
type="button"
className="btn btn-primary"
size="sm"
onClick={this.toggle}
>
Edit Story
</button>
) : (
<h4 className="mb-3 ml-4">Please log in to manage stories</h4>
)}
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}>Edit story</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<Label for="story">Title</Label>
<Input
type="text"
name="title"
id="story"
onChange={this.onChange}
value={this.state.title}
/>
<Label for="story">Story</Label>
<Input
type="textarea"
name="body"
rows="20"
value={this.state.body}
onChange={this.onChange}
/>
<button
type="button"
className="btn btn-dark"
style={{ marginTop: "2rem" }}
onClick={this.onSubmit}
>
Edit story
</button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = state => ({
story: state.story,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ updateStory }
)(UpdateStoryModal);
Yes, you want to return the updated item from your MongoDB database so that you have something to work with in your reducer. It looks like you've setup your action-creator to be prepared for that type of logic. So we just need to make a couple updates:
In your express route you would want something like:
router.put("/:_id", auth, (req, res) => {
//this returns a promise
Item.findByIdAndUpdate(
req.params._id,
req.body,
{ new: false, useFindAndModify: false },
() => {}
)
.then((updatedItem) => {
res.json(updatedItem) //we capture this via our promise-handler on the action
})
.catch((error) => {
return res.status(400).json({ couldnotupdate: "could not update item"})
})
});
Then we can tap into that updated item using res.data in your action-creator promise-handler
export const updateStory = story => (dispatch, getState) => {
axios
.put(`/api/stories/${story.id}`, story, tokenConfig(getState))
.then(res => {
dispatch({
type: UPDATE_STORY,
payload: res.data
});
})
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
Now that you have the updated item as an action-payload, we need to update your reducer:
case UPDATE_STORY:
return {
...state,
stories: state.stories.map((story) => {
if(story._id == action.payload._id){
return{
...story,
...action.payload
} else {
return story
}
}
})
};
With that you should be able to take the updated story from your back-end and have it reflected to the front.

React Redux PUT request failing

REACT Redux PUT request gives me following error:
"Proxy error: Could not proxy request /api/stories/5ccf12b5f6b087c2a3fcc21b from localhost:3000 to http://localhost:5002.
[1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNRESET)."
I made sample React Redux CRUD app based on #Brad Traversy tutorial and GET, POST, DELETE requests works fine.
API with mongoose:
const express = require("express");
const router = express.Router();
const auth = require("../../middleware/auth");
// Item Model
const Item = require("../../models/stories");
// #route GET api/items
// #desc Get All Items
// #access Public
router.get("/", (req, res) => {
Item.find()
.sort({ date: -1 })
.then(items => res.json(items));
});
// #route POST api/items
// #desc Create An Item
// #access Private
router.post("/", auth, (req, res) => {
const newItem = new Item({
title: req.body.title,
body: req.body.body,
author: "Les Frazier"
});
newItem.save().then(item => res.json(item));
});
router.put("/:_id", auth, (req, res) => {
var query = { _id: req.params._id };
var update = {
_id: req.params._id,
title: req.params.title,
body: req.params.body
};
var options = { new: true, useFindAndModify: false };
Item.findByIdAndUpdate(req.params._id, { $set: update }, options);
});
// #route DELETE api/items/:id
// #desc Delete A Item
// #access Private
router.delete("/:id", auth, (req, res) => {
Item.findById(req.params.id)
.then(item => item.remove().then(() => res.json({ success: true })))
.catch(err => res.status(404).json({ success: false }));
});
module.exports = router;
Child component for updating(PUT) data that is failing
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input
} from "reactstrap";
import { connect } from "react-redux";
import { updateStory, deleteStory } from "../../actions/storyActions";
import PropTypes from "prop-types";
class UpdateStoryModal extends Component {
state = {
modal: false,
title: this.props.story.stories.find(
story => story._id === this.props.value
).title,
body: this.props.story.stories.find(story => story._id === this.props.value)
.body
};
static propTypes = {
isAuthenticated: PropTypes.bool
};
toggle = () => {
this.setState({
modal: !this.state.modal
});
};
onChange = e => {
e.target.name === "title"
? this.setState({ title: e.target.value })
: this.setState({ body: e.target.value });
};
//PUT
onSubmit = e => {
e.preventDefault();
const updateStory = {
_id: this.props.value,
title: this.state.title,
body: this.state.body
};
this.props.updateStory(updateStory);
// Close modal
this.toggle();
};
render() {
return (
<div>
{this.props.isAuthenticated ? (
<Button color="primary" size="sm" onClick={this.toggle}>
Edit Story
</Button>
) : (
<h4 className="mb-3 ml-4">Please log in to manage stories</h4>
)}
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}>Edit story</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="story">Title</Label>
<Input
type="text"
name="title"
id="story"
onChange={this.onChange}
value={this.state.title}
/>
<Label for="story">Story</Label>
<Input
type="textarea"
name="body"
rows="20"
value={this.state.body}
onChange={this.onChange}
/>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Edit story
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = state => ({
story: state.story,
title: state.title,
body: state.body,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ updateStory, deleteStory }
)(UpdateStoryModal);
Child component that is adding(POST) data and works fine
import React, { Component } from "react";
import {
Button,
Modal,
ModalHeader,
ModalBody,
Form,
FormGroup,
Label,
Input
} from "reactstrap";
import { connect } from "react-redux";
import { addStory } from "../../actions/storyActions";
import PropTypes from "prop-types";
class AddStoryModal extends Component {
state = {
modal: false,
title: "",
body: ""
};
static propTypes = {
isAuthenticated: PropTypes.bool
};
toggle = () => {
this.setState({
modal: !this.state.modal
});
};
onChange = e => {
e.target.name === "title"
? this.setState({ title: e.target.value })
: this.setState({ body: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const newStory = {
title: this.state.title,
body: this.state.body
};
this.props.addStory(newStory);
// Close modal
this.toggle();
};
render() {
return (
<div>
{this.props.isAuthenticated ? (
<Button
color="dark"
style={{ marginBottom: "2rem" }}
onClick={this.toggle}
>
Add Story
</Button>
) : (
<h4 className="mb-3 ml-4">Please log in to manage stories</h4>
)}
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}>Add new story</ModalHeader>
<ModalBody>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="story">Title</Label>
<Input
type="text"
name="title"
id="story"
onChange={this.onChange}
/>
<Label for="story">Story</Label>
<Input
type="textarea"
name="body"
rows="20"
onChange={this.onChange}
/>
<Button color="dark" style={{ marginTop: "2rem" }} block>
Add Story
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
const mapStateToProps = state => ({
title: state.title,
body: state.body,
isAuthenticated: state.auth.isAuthenticated
});
export default connect(
mapStateToProps,
{ addStory }
)(AddStoryModal);
Reducer
import {
GET_STORIES,
ADD_STORY,
DELETE_STORY,
STORIES_LOADING,
UPDATE_STORY
} from "../actions/types";
const initialState = {
stories: [],
loading: false
};
export default function(state = initialState, action) {
switch (action.type) {
case GET_STORIES:
return {
...state,
stories: action.payload,
loading: false
};
case DELETE_STORY:
return {
...state,
stories: state.stories.filter(story => story._id !== action.payload)
};
case ADD_STORY:
return {
...state,
stories: [action.payload, ...state.stories]
};
case UPDATE_STORY:
return {
...state,
stories: state.stories.map(story =>
story._id === action.payload._id ? (story = action.payload) : story
)
};
case STORIES_LOADING:
return {
...state,
loading: true
};
default:
return state;
}
}
Action
import axios from "axios";
import {
GET_STORIES,
ADD_STORY,
DELETE_STORY,
UPDATE_STORY,
STORIES_LOADING
} from "./types";
import { tokenConfig } from "./authActions";
import { returnErrors } from "./errorActions";
export const getStories = () => dispatch => {
dispatch(setStoriesLoading());
axios
.get("/api/stories")
.then(res =>
dispatch({
type: GET_STORIES,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const addStory = story => (dispatch, getState) => {
axios
.post("/api/stories", story, tokenConfig(getState))
.then(res =>
dispatch({
type: ADD_STORY,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const updateStory = story => (dispatch, getState) => {
axios
.put(`/api/stories/${story._id}`, story, tokenConfig(getState))
.then(res =>
dispatch({
type: UPDATE_STORY,
payload: res.data
})
)
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const deleteStory = id => (dispatch, getState) => {
axios
.delete(`/api/stories/${id}`, tokenConfig(getState))
.then(res =>
dispatch({
type: DELETE_STORY,
payload: id
})
)
.catch(err =>
dispatch(returnErrors(err.response.data, err.response.status))
);
};
export const setStoriesLoading = () => {
return {
type: STORIES_LOADING
};
};
Ok so I found main problem...
I have replaced this code"
Item.findByIdAndUpdate(req.params._id, { $set: update }, options);
with this:
Item.findByIdAndUpdate(
req.params._id,
req.body,
{ new: false, useFindAndModify: false },
() => {
console.log("done");
}
);
And the record is being updated now in db. So the main problem is gone.
But whenever I refresh a page I'm still getting this:
Proxy error: Could not proxy request /api/stories/5ccf398fe278beca5efa3d23 from localhost:3000 to http://localhost:5002.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNRESET).

Resources