React Form - Show Message if Successfully entered into (MongoDB) Database - reactjs

I'm sorry I'm sure this question has been answered before I did a few searches and couldn't find it.
I just am trying to figure out a way to submit a form , and get a "Successfully Submitted your information" response to the user, and clear the form.
I made a small form to make it simple - any help would be greatly appreciated.
**Edit - At the moment you click submit and everything submits into the MongoDB correctly but nothing happens on the Client side. Would like something to show that the data has indeed been added
form.js Component
import React, { Component } from 'react';
import {
Button,
Form,
FormGroup,
Label,
Input
} from 'reactstrap';
import { connect } from 'react-redux';
import { addItem } from '../actions/itemActions';
class Register extends Component {
state = {
name: '',
email: ''
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onSubmit = e => {
e.preventDefault();
const newItem = {
name: this.state.name,
email: this.state.email
};
this.props.addItem(newItem);
this.setState({
name: "",
email: ""
});
};
render() {
return (
<div>
<Form onSubmit={this.onSubmit}>
<FormGroup>
<Label for="item">Name</Label>
<Input
type="text"
name="name"
id="item"
placeholder="Full Name"
onChange={this.onChange}
/>
<Label for="email">Email</Label>
<Input
type="text"
name="email"
id="item"
placeholder="Email"
onChange={this.onChange}
/>
<Button color="dark" style={{ marginTop: '1rem' }} block>
Register
</Button>
</FormGroup>
</Form>
</div>
);
}
}
const mapStateToProps = state => ({
item: state.item
});
export default connect(
mapStateToProps,
{ addItem }
)(Register);
ItemActions.js
import axios from 'axios';
import { GET_ITEMS, ADD_ITEM, ITEMS_LOADING } from './types';
export const getItems = () => dispatch => {
dispatch(setItemsLoading());
axios.get('/api/items').then(res =>
dispatch({
type: GET_ITEMS,
payload: res.data
})
);
};
export const addItem = item => dispatch => {
axios.post('/api/items', item).then(res =>
dispatch({
type: ADD_ITEM,
payload: res.data
})
);
};
/* If I wanted to include a delete item request
export const deleteItem = id => dispatch => {
axios.delete(`/api/items/${id}`).then(res =>
dispatch({
type: DELETE_ITEM,
payload: id
})
);
};*/
export const setItemsLoading = () => {
return {
type: ITEMS_LOADING
};
};
items.js
const express = require('express');
const router = express.Router();
// Item Model
const Item = require('../../models/Items');
// route GET api/items
router.get('/', (req, res) => {
Item.find()
.sort({ name: 1 })
.then(items => res.json(items));
});
// route POST api/items
router.post('/', (req, res) => {
const newItem = new Item({
name: req.body.name,
email: req.body.email
});
newItem.save();
});
module.exports = router;

Related

React: A non-serializable value was detected in the state

I'm trying to make a simple login/logout feature in my app using firebase auth rest API, I'm using redux to let user log in and logout, the user get registered perfectly in the firebase but when I hit Signup & Login button of the form, I'm getting this error 👇
With redux toolkit I'm wondering what's going wrong with my initialState of login function.
Here is my code: -
//login-store.js
const { configureStore, createSlice } = require("#reduxjs/toolkit");
const userAuth = createSlice({
name: "login",
initialState: {
token: "",
isLoggedIn: false,
login: (token) => {},
logout: () => {},
},
reducers: {
logginOut(state) {
state.isLoggedIn = false;
state.logout = () => {
localStorage.removeItem("userLoginToken");
};
},
loggingIn(state) {
state.isLoggedIn = true;
state.token = localStorage.getItem("userLoginToken");
state.login = (token) => {
return localStorage.setItem("userLoginToken", token);
};
},
},
});
const authStore = configureStore({
reducer: userAuth.reducer,
});
export const userAuthAction = userAuth.actions;
export default authStore;
And here I'm having my login and signup feature. Also there is one more problem, whenever I click New User button below the submit button, I immediately get the alert popup (written with comment below) I don't know how am I sending fetch request while switching the form...
//Login.js
import React, { useRef, useState } from "react";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { userAuthAction } from "../store/login-store";
import classes from "./pages.module.css";
export default function Login() {
const dispatch = useDispatch();
const [isLogin, setIsLogin] = useState(true);
const navigate = useNavigate();
const emailInput = useRef();
const passwordInput = useRef();
const switchAuthTextHandler = () => {
setIsLogin((prevState) => !prevState);
};
const loginAuthHandler = (e) => {
e.preventDefault();
const enteredEmailValue = emailInput.current.value;
const enteredPasswordValue = passwordInput.current.value;
let authUrl;
if (isLogin) {
// when logging in
authUrl =
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyB3Mbv38Ju8c9QedQzqX3QvufTCOXhkU0c";
} else {
// when signing up
authUrl =
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyB3Mbv38Ju8c9QedQzqX3QvufTCOXhkU0c";
}
fetch(authUrl, {
method: "POST",
body: JSON.stringify({
email: enteredEmailValue,
password: enteredPasswordValue,
returnSecureToken: true,
}),
headers: {
"Content-type": "application/json",
},
})
.then((res) => {
if (res.ok) {
return res.json();
} else {
return res.json().then((data) => {
// getting alert popup immediately after switching the form
alert(data.error.message);
});
}
})
.then((data) => {
dispatch(userAuthAction.loggingIn(data.idToken));
navigate("/");
console.log(data);
})
.catch((err) => {
console.error(err.message);
});
};
return (
<div className={classes.loginWrapper}>
<form onSubmit={loginAuthHandler}>
<h4>{isLogin ? "Login" : "Signup"}</h4>
<div className={classes.form_group}>
<label htmlFor="email">Email</label>
<input type="email" id="email" ref={emailInput} />
</div>
<div className={classes.form_group}>
<label htmlFor="password">Password</label>
<input type="password" id="password" ref={passwordInput} />
</div>
<div className={classes.form_group}>
<button type="submit">{isLogin ? "Login" : "Signup"}</button>
</div>
<div className={classes.form_group}>
<button className={classes.newUser} onClick={switchAuthTextHandler}>
{isLogin ? "New User?" : "Already have account"}
</button>
</div>
</form>
</div>
);
}
Error while siging up the new user:-
We should not store function references in the redux store. They are not serializable, and states should be serializable in redux state.

redux props receiving data twice

I am using redux to get the async data and response. In the below component when i post recipe and from server i get response through redux the success modal popup twice. reducer is running only once i have checked eveything, only component has problem. the problem could be with the lifecycle method.
import React, { Component } from 'react';
import 'antd/dist/antd.css';
import {withRouter} from 'react-router-dom';
import {connect} from 'react-redux';
import * as actionCreators from '../../actions/recipe-action/index';
import { Modal, Button } from "antd";
import Spinner from '../../UI/spinner';
class PostRecipe extends Component {
state = {
url: '',
visible: false,
}
showModal = () => {
this.setState({ visible: true });
};
onChangeHandler = (e) => {
this.setState({[e.target.name]: e.target.value});
}
handleOk = e => {
this.props.recipe(this.state.url);
this.setState({url: ""});
this.setState({ visible: false });
};
handleCancel = e => {
this.setState({ visible: false });
};
render() {
const { postRecipes } = this.props;
if(postRecipes.loading) {
return <Spinner />;
}else if(postRecipes.success.ok) {
// this success model popup twice after uploading the recipe
Modal.success({
content: "Recipe Uploaded"
});
}else if(postRecipes.failure.error) {
Modal.error({
title: "Error while uploading recipe",
});
}
return (
<div>
<div>
<Button type="primary" onClick={this.showModal}>
Add Recipe
</Button>
<Modal
title="Add Recipe"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<input
style={{ width: "100%", padding: "5px", fontSize: "15px" }}
type="text"
placeholder="enter the url"
name="url"
value={this.state.url}
onChange={this.onChangeHandler}
/>
</Modal>
</div>
</div>
);
}
}
const mapStateToProps = ({ postRecipeReducers }) => {
const { recipe: { post: postRecipes } } = postRecipeReducers;
return {
postRecipes
}
};
const mapStateToDispatch = dispatch => {
return {
recipe: (url) => dispatch(actionCreators.postRecipes(url))
}
}
export default withRouter(connect(mapStateToProps, mapStateToDispatch)(PostRecipe));
// my action creators
import {POST_RECIPE_LOADING, POST_RECIPE_SUCCESS, POST_RECIPE_FAILURE, POST_RECIPE_RESET} from '../types';
import {GET_RECIPE_LOADING, GET_RECIPE_SUCCESS, GET_RECIPE_FAILURE, GET_RECIPE_RESET} from '../types';
import Parse from 'parse';
export const postRecipes = (url) => async(dispatch) => {
try {
dispatch({type: POST_RECIPE_LOADING, payload: null});
const {data} = await Parse.Cloud.run('post_recipe', {url: url});
dispatch({type: POST_RECIPE_SUCCESS, payload: data});
} catch(e) {
dispatch({type: POST_RECIPE_FAILURE, payload: {message: e.message}})
}
}
export const getRecipes = () => async (dispatch) => {
try {
dispatch({type: GET_RECIPE_LOADING, payload: null});
const {data} = await Parse.Cloud.run('get_recipe');
dispatch({type: GET_RECIPE_SUCCESS, payload: data});
} catch(e) {
dispatch({type: GET_RECIPE_FAILURE, payload: {message: e.message}})
}
};
Try this:
handleOk = e => {
this.props.recipe(this.state.url);
this.setState({url: "", visible: false});
};
state variable of class is a object with two keys: url and visible. You have to set both at once.
I would try implementing a constructor function to make sure that you have this bound to your local state.
In this code block,
handleOk = e => {
this.props.recipe(this.state.url);
this.setState({url: ""});
this.setState({ visible: false });
};
you could set the whole state in one line like this,
handleOk = e => {
this.props.recipe(this.state.url);
this.setState({url: "", visible: false});
}
I don't know that this will fix your problem. Just a bit of house keeping.

In React-Redux app, trying to pre-fill the default value in Edit Component with current api calls value

In my reactredux app, There is a peculiar situaton where I am currently trying to pre-fill my input field in Edit component but the thing is ,Its getting filled but not with current api calls but with last api calls that happens inside componentDidMount().I tried to clear the object too but all in vain. Kindly suggest
ProfileEdit.js component
import React, { Component } from 'react';
import '../App.css';
import {connect} from 'react-redux';
import {profileFetchDetail} from '../actions/profile';
import { withRouter } from 'react-router-dom';
class ProfileEdit extends Component {
constructor(props){
super(props);
this.state = {
firstName: '',
lastName: '',
emailId: '',
}
}
componentDidMount(){
const id = this.props.match.params.id;
this.props.profileFetchDetail(id);
this.setState({
firstName: this.props.profile.firstName,
lastName: this.props.profile.lastName,
emailId: this.props.profile.emailId
})
}
render() {
const {firstName,lastName,emailId} = this.state;
console.log(this.props.profile);
return (
<form name="profileCreate" className="profile-form">
<div className="form-control">
<label htmlFor="firstName">First Name</label><br/>
<input type="text" id="firstName" defaultValue={firstName}
name="firstName" placeholder="First Name"
/>
</div>
<div className="form-control">
<label htmlFor="LastName">Last Name</label><br/>
<input type="text" id="LastName" defaultValue={lastName}
name="lastName" placeholder="Last Name"
/>
</div>
<div className="form-control">
<label htmlFor="email">Email</label><br/>
<input type="email" id="email" defaultValue={emailId}
/>
</div>
<div className="form-action">
<input type="submit" value="Click here" />
</div>
</form>
)
}
}
const mapStateToProps = state => ({
profile: state.profile.profile
})
export default connect(mapStateToProps, {profileFetchDetail})(withRouter(ProfileEdit));
Action creators, here profileFetchDetail() is of our interest
import api from '../api';
// profile create
export const profileAdd = (formData, history) => async dispatch => {
console.log(formData);
const config = {
headers : { 'Content-Type': 'application/json' }
}
try {
await api.post('/api/profile/create', formData, config);
dispatch({ type: 'CREATE_PROFILE', payload: formData });
history.push('/list');
} catch (error) {
console.log(error);
}
}
// profile get all list
export const profileFetch = () => async dispatch => {
try {
const res = await api.get('/api/profile/list');
dispatch({ type: 'GET_PROFILE', payload: res.data });
} catch (error) {
console.log(error);
}
}
// profile get single list item corresponding to id
export const profileFetchDetail = (id) => async dispatch => {
dispatch({ type: 'CLEAR_PROFILE' });
try {
const res = await api.get(`/api/profile/${id}`);
dispatch({ type: 'GET_PROFILE_SINGLE', payload: res.data });
} catch (error) {
console.log(error);
}
}
// profile delete
export const profileDelete = (id) => async dispatch => {
dispatch({ type: 'CLEAR_PROFILE' });
try {
const res = await api.delete(`/api/profile/${id}/delete`);
dispatch({ type: 'DELETE_PROFILE', payload: res.data });
dispatch(profileFetch());
} catch (error) {
console.log(error);
}
}
ProfileReducers
const initialState = {
profiles:[],
profile:{}
};
export default (state = initialState, action) => {
switch (action.type) {
case 'CREATE_PROFILE':
return {...state, profiles: [...state.profiles, action.payload]};
case 'GET_PROFILE':
return {...state, profiles: action.payload};
case 'GET_PROFILE_SINGLE':
return {...state, profile: action.payload};
case 'CLEAR_PROFILE':
return {...state, profile: {}};
case 'DELETE_PROFILE':
return {...state, profiles: state.profiles.filter( item => item._id !== action.payload) };
default:
return state;
}
};
First time it loads perfectly on clicking edit button then the issue happens on clicking any other edit button.Pasting the example of 2 api calls inside componentDidMount().
In the attached image, the last api request in sequence displayed is the currently made request.Api made detail
Note: Till now I am not trying to edit it just prefilling data,where issue happening.

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