React app requires hard refresh after successful login - javascript

I'm struggling to debug a problem and I'd appreciate any help the community might be able to offer. I'm building my first React app and have built a working Login feature, but after every successful login the user is forced to hard refresh his/her browser in order see the app in a "logged in" state. There is no error logged to the browser console, but our DevTools monitor shows the following error:
"TypeError: Cannot read property 'setState' of undefined"
What's funny is that the login authentication first succeeds, and then immediately seems to try again and fails. After clicking "login," the user must hard refresh the web page in order to make it appear that the login has worked.
I'm stumped. Can anyone see anything wrong with my code? Thank you very much in advance for taking a look!
Here's our LoginPage jsx file that contains the actual login web form:
import React from 'react';
import { Button, Form, FormGroup, Label, Input } from 'reactstrap';
export default class LoginPage extends React.Component {
constructor(props) {
super(props);
//bound functions
this.compileFormData = this.compileFormData.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
//component state
this.state = {
email: '',
password: '',
};
}
//update state as email value changes
handleEmailChange(e) {
this.setState({ email: e.target.value });
}
//update state as password value changes
handlePasswordChange(e) {
this.setState({ password: e.target.value });
}
compileFormData() {
const { loginFunction } = this.props;
const formData = this.state;
loginFunction(formData);
}
render() {
return (
<div className="row justify-content-center">
<div className="col-10 col-sm-7 col-md-5 col-lg-4">
<Form>
<FormGroup>
<Label for="exampleEmail">Email</Label>
<Input
type="email"
name="email"
id="userEmail"
placeholder="test#mccre.com"
value={this.state.email}
onChange={this.handleEmailChange}
/>
</FormGroup>
<FormGroup>
<Label for="examplePassword">Password</Label>
<Input
type="password"
name="password"
id="userPassword"
placeholder="password"
value={this.state.password}
onChange={this.handlePasswordChange}
/>
</FormGroup>
<Button onClick={this.compileFormData}>Log In</Button>
</Form>
</div>
</div>
);
}
}
Here's our login page Container that renders the login page:
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { logUserIn } from '../../actions/authentication';
import LoginPage from './LoginPage';
export class LoginPageContainer extends React.Component {
constructor(props) {
super(props);
//bound functions
this.logUserInFunction = this.logUserInFunction.bind(this);
}
logUserInFunction(userData) {
const { dispatch } = this.props;
dispatch(logUserIn(userData));
}
render() {
const { authentication } = this.props;
if (authentication.isLoggedIn) {
return (
<Redirect to="/" />
);
}
return (
<div>
<LoginPage loginFunction={this.logUserInFunction} />
</div>
);
}
}
function mapStateToProps(state) {
return {
authentication: state.authentication,
};
}
export default connect(mapStateToProps)(LoginPageContainer);
Here's our API endpoint in which we actually make the database query:
const express = require('express');
const mongoose = require('mongoose');
const passport = require('passport');
const User = require('../../models/user.js');
const router = express.Router();
//configure mongoose promises
mongoose.Promise = global.Promise;
//POST to /register
router.post('/register', (req, res) => {
//Create a user object to save, using values from incoming JSON
const newUser = new User({
username: req.body.username,
firstName: req.body.firstName,
lastname: req.body.lastName,
email: req.body.email,
});
//Save, via passport's "register" method, the user
User.register(newUser, req.body.password, (err, user) => {
//If there's a problem, send back a JSON object with the error
if (err) {
return res.send(JSON.stringify({ error: err }));
}
// Otherwise, for now, send back a JSON object with the new user's info
return res.send(JSON.stringify(user));
});
});
//POST to /login
router.post('/login', async (req, res) => {
//look up user by their email
const query = User.findOne({ email: req.body.email });
const foundUser = await query.exec();
//If they exist, they'll have a username, so add that to our body
if (foundUser) {
req.body.username = foundUser.username;
}
passport.authenticate('local') (req, res, () => {
//If logged in, we should have use info to send back
if (req.user) {
return res.send(JSON.stringify(req.user));
}
//Otherwise return an error
return res.send(JSON.stringify({ error: 'There was an error logging in' }));
});
});
//GET to /checksession
router.get('/checksession', (req, res) => {
if (req.user) {
return res.send(JSON.stringify(req.user));
}
return res.send(JSON.stringify({}));
});
//GET to /logout
router.get('/logout', (req, res) => {
req.logout();
return res.send(JSON.stringify(req.user));
});
module.exports = router;
Here's the action file in which we define the logUserIn() function:
import { decrementProgress, incrementProgress } from './progress';
import 'whatwg-fetch';
//Action Creators
export const loginAttempt = () => ({ type: 'AUTHENTICATION_LOGIN_ATTEMPT' });
export const loginFailure = error => ({ type: 'AUTHENTICATION_LOGIN_FAILURE', error });
export const loginSuccess = json => ({ type: 'AUTHENTICATION_LOGIN_SUCCESS', json });
export const logoutFailure = error => ({ type: 'AUTHENTICATION_LOGOUT_FAILURE', error });
export const logoutSuccess = () => ({ type: 'AUTHENTICATION_LOGOUT_SUCCESS' });
export const sessionCheckFailure = () => ({ type: 'AUTHENTICATION_SESSION_CHECK_FAILURE'});
export const sessionCheckSuccess = json => ({ type: 'AUTHENTICATION_SESSION_CHECK_SUCCESS', json });
//Check User Session
export function checkSession() {
return async (dispatch) => {
//contact the API
await fetch(
//where to contact
'/api/authentication/checksession',
//what to send
{
method: 'GET',
credentials: 'same-origin',
},
)
.then((response) => {
if (response.status === 200) {
return response.json();
}
return null;
})
.then((json) => {
if (json.username) {
return dispatch(sessionCheckSuccess(json));
}
return dispatch(sessionCheckFailure());
})
.catch((error) => dispatch(sessionCheckFailure(error)));
};
}
//Log user in
export function logUserIn(userData) {
return async (dispatch) => {
//turn on spinner
dispatch(incrementProgress());
//register that a login attempt is being made
dispatch(loginAttempt());
//contact login API
await fetch(
//where to contact
'http://localhost:3000/api/authentication/login',
//what to send
{
method: 'POST',
body: JSON.stringify(userData),
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
},
).then((response) => {
if (response.status === 200) {
return response.json();
}
return null;
})
.then((json) => {
if (json) {
dispatch(loginSuccess(json));
this.setState({ redirect: true });
} else {
dispatch(loginFailure(new Error('Authentication Failed')));
}
}).catch((error) => {
dispatch(loginFailure(new Error(error)));
});
//turn off spinner
dispatch(decrementProgress());
};
}
//Log user out
export function logUserOut() {
return async (dispatch) => {
//turn on spinner
dispatch(incrementProgress());
//contact the API
await fetch(
//where to contact
'/api/authentication/logout',
//what to send
{
method: 'GET',
credentials: 'same-origin',
},
)
.then((response) => {
if (response.status === 200) {
dispatch(logoutSuccess());
} else {
dispatch(logoutFailure(`Error: ${response.status}`));
}
})
.catch((error) => {
dispatch(logoutFailure(error));
});
//turn off spinner
return dispatch(decrementProgress());;
};
}
Finally, here's the reducer file that is supposed to update the application's state depending on authentication success / failure:
const initialState = {
firstName: '',
id: '',
isLoggedIn: false,
isLoggingIn: false,
lastName: '',
username: '',
};
export default function reducer(state = initialState, action) {
switch (action.type) {
case 'AUTHENTICATION_LOGIN_ATTEMPT': {
const newState = Object.assign({}, state);
newState.isLoggingIn = true;
return newState;
}
case 'AUTHENTICATION_LOGIN_FAILURE':
case 'AUTHENTICATION_SESSION_CHECK_FAILURE':
case 'AUTHENTICATION_LOGOUT_SUCCESS': {
const newState = Object.assign({}, initialState);
return newState;
}
case 'AUTHENTICATION_LOGIN_SUCCESS':
case 'AUTHENTICATION_SESSION_CHECK_SUCCESS': {
const newState = Object.assign({}, state);
newState.firstName = action.json.firstName;
newState.id = action.json._id;
newState.isLoggedIn = true;
newState.isLoggingIn = false;
newState.lastName = action.json.lastName;
newState.username = action.json.username;
return newState;
}
case 'AUTHENTICATION_LOGOUT_FAILURE': {
//todo: hanle error
return state;
}
default: {
return state;
}
}
}

Found the solution: "the this.setState({ redirect: true });" line needed to be removed from the action file.

Related

What is the best way to connect to node.js API's GET method from component

I am still relatively new to node.js and I am wondering what the best way to call my API's GET method from within this next.js component. So far I have my DemoForm.js component here:
import { useState } from 'react'
import { useRouter } from 'next/router'
import { mutate } from 'swr'
const DemoForm = ({ req, formId, demoForm, forNewDemo = true }) => {
const router = useRouter()
const contentType = 'application/json'
const [errors, setErrors] = useState({})
const [message, setMessage] = useState('')
const [demoName, setDemoName] = useState(demoForm.demoName || 'demo name')
const [response, setResponse] = useState (null)
const makeRequest = async () => {
const res = await fetch('api/demos')
setResponse({
status: res.status,
body: await res.json(),
limit: res.headers.get('X-RateLimit-Limit'),
remaining: res.headers.get('X-RateLimit-Remaining'),
})
}
const [form, setForm] = useState({
demo_token: demoForm.demo_token,
demo_name: demoForm.demo_name,
})
/* The PUT method edits an existing entry in the mongodb database. */
const putData = async (form) => {
const { id } = router.query
try {
const res = await fetch(`/api/demos/${id}`, {
method: 'PUT',
headers: {
Accept: contentType,
'Content-Type': contentType,
},
body: JSON.stringify(form),
})
// Throw error with status code in case Fetch API req failed
if (!res.ok) {
throw new Error(res.status)
}
const { data } = await res.json()
mutate(`/api/demos/${id}`, data, false) // Update the local data without a revalidation
router.push('/')
} catch (error) {
setMessage('Failed to update')
}
}
/* The POST method adds a new entry in the mongodb database. */
const postData = async (form) => {
try {
const res = await fetch('/api/demos', {
method: 'POST',
headers: {
Accept: contentType,
'Content-Type': contentType,
},
body: JSON.stringify(form),
})
// Throw error with status code in case Fetch API req failed
if (!res.ok) {
throw new Error(res.status)
}
router.push('/')
} catch (error) {
setMessage('Failed to add new function')
}
}
const handleChange = (e) => {
const target = e.target
const value =
target.name === 'demo_token' ? target.checked : target.value
const name = target.name
setForm({
...form,
[name]: value,
})
}
/* Makes sure demo info is filled for demo name, owner name, species, and image url*/
const formValidate = () => {
let err = {}
// if (!form.demo_token) err.demo_token = 'Checkbox selection required'
if (!form.demo_name) err.demo_name = 'Name is required'
return err
}
const handleSubmit = (e) => {
e.preventDefault()
const errs = formValidate()
if (Object.keys(errs).length === 0) {
forNewDemo ? postData(form) : putData(form)
} else {
setErrors({ errs })
}
}
return (
<>
<form id={formId} onSubmit={handleSubmit}>
<span className="flex flex-row justify-center">
<label htmlFor="demo_name">Name</label>
<input
name="demo_name"
value={form.demo_name}
onChange={handleChange}
/>
<br />
</span>
<span className="flex flex-row justify-center">
<label htmlFor="demo_token">Pro?</label>
<input
type="checkbox"
name="demo_token"
checked={form.demo_token}
onChange={handleChange}
/>
<br />
</span>
<span className="flex flex-row justify-center">
<button type="submit" className=" bg-gray-800 btn-sm text-teal-200 hover:text-teal-300 flex-row justify-start pl-4" onClick={() => makeRequest()}>Make Request</button>
{/* {response && (
<code>
<pre>{JSON.stringify(response, null, 2)}</pre>
</code>
)} */}
</span>
<p>{message}</p>
<div>
{Object.keys(errors).map((err, index) => (
<li key={index}>{err}</li>
))}
</div>
</form>
</>
)
}
export default DemoForm
and here is the API
pages/api/demos/[id].js
import dbConnect from '../../../lib/dbConnect'
import Demo from '../../../models/Demo'
export default async function handler(req, res) {
const {
query: { id },
method,
} = req
await dbConnect()
switch (method) {
case 'GET' /* Get a model by its ID */:
try {
const demo = await Demo.findById(id)
if (!demo) {
return res.status(400).json({ success: false })
}
res.status(200).json({ success: true, data: demo })
} catch (error) {
res.status(400).json({ success: false })
}
break
case 'PUT' /* Edit a model by its ID */:
try {
const demo = await Demo.findByIdAndUpdate(id, req.body, {
new: true,
runValidators: true,
})
if (!demo) {
return res.status(400).json({ success: false })
}
res.status(200).json({ success: true, data: demo })
} catch (error) {
res.status(400).json({ success: false })
}
break
case 'DELETE' /* Delete a model by its ID */:
try {
const deletedDemo = await Demo.deleteOne({ _id: id })
if (!deletedDemo) {
return res.status(400).json({ success: false })
}
res.status(200).json({ success: true, data: {} })
} catch (error) {
res.status(400).json({ success: false })
}
break
default:
res.status(400).json({ success: false })
break
}
}
pages/api/demos/index.js
import dbConnect from '../../../lib/dbConnect'
import Demo from '../../../models/Demo'
import fs from 'fs'
const shell = require('shelljs');
export default async function handler(req, res) {
const {
method,
body,
} = req
await dbConnect()
switch (method) {
case 'GET':
try {
const demos = await Demo.find({}) /* find all the data in our database */
res.status(200).json({ success: true, data: demos })
} catch (error) {
res.status(400).json({ success: false })
}
break
case 'POST':
try {
const demo = await Demo .create(
req.body
) /* create a new model in the database */
res.status(201).json({ success: true, data: demo })
} catch (error) {
res.status(400).json({ success: false })
}
break
default:
res.status(400).json({ success: false })
break
}
}
The form is setup to work with my API's post and put methods, however, I am needing to call the GET method to essentially map out all of the demos by there ${id} so they can be rendered on screen. I am having a tough time doing this from within my Next.js component. ANY help would be greatly appreciated!
Thanks y'all...

remember me checkbox in login that using token in react js

I want to add a Clickable “Remember Me” checkbox in my login page that tells the browser to save a cookie so that if you close out the window for the site without signing out, the next time you go back, you will be signed back in automatically.that can save username and password
export const getUser = () => {
const userStr = sessionStorage.getItem("user");
if (userStr) return JSON.parse(userStr);
else return null;
};
export const getToken = () => {
return sessionStorage.getItem("token") || null;
};
export const setUserSession = (token, user) => {
sessionStorage.setItem("token", token);
sessionStorage.setItem("user", JSON.stringify(user));
};
export const removeUserSession = () => {
sessionStorage.removeItem("token");
sessionStorage.removeItem("user");
};
export const handleSuccessfulLogin = async (token, rememberMe) => {
localStorage.setItem("token", token);
localStorage.setItem("rememberme", rememberMe);
};
export const handleLogout = () => {
localStorage.clear();
};
This is my login that work with api
const handelLogin = () => {
setError(null);
setLoading(true);
axios
.post("https://www.mecallapi.com/api/login", {
username: username,
password: password,
})
.then((response) => {
setLoading(false);
setUserSession(response.data.token, response.data.user);
navigate("/Dashboard");
})
.catch((error) => {
setLoading(false);
if (error.response.status === 401 || error.response.status === 400) {
setError(error.response.data.message);
} else {
setError("somthing went wrong ,please try again");
}
});
};
This is my remember me checkbox
<div className="login-bottom">
<Checkbox {...label} />
</div>

Why is my API getting undefined values from fetch calls?

In my login system for my react project, I have created a loginForm component that sends a username and password my backend. I know that the backend is properly called on submit due to my console logs in the api returning "undefined" for the username and password values entered. Whatever I have done, I have not been able to get this to properly be sent to my api for authentication. Does anyone have any idea why this may be the case? The code is listed below:
server.js :
const app = express();
const path = require('path');
const mysql = require('mysql');
const cors = require('cors');
const session = require('express-session');
const MySQLStore = require('express-mysql-session');
// app.use(express.static(path.join(__dirname, 'client')));
app.use(express.json());
app.use(cors())
const port = 5000;
app.listen(port, () => `Server running on port ${port}`);
app.post('/login', (req, res) => {
console.log(req.body)
let username = req.body.username;
let password = req.body.password;
console.log(username)
console.log(password)
})
InputField.js (my input component. It consists of a SubmitButton component, and inputField component)
import InputField from '../components/InputField';
import SubmitButton from '../components/SubmitButton';
import UserStore from '../Stores/UserStore';
class LoginForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: '',
buttonDisabled: false
}
}
SetInputValue(property, val) {
val = val.trim();
if (val.length > 12) {
return;
}
this.setState({
[property]: val
})
}
resetForm() {
this.setState({
username: '',
password: '',
buttonDisabled: false
})
}
async doLogin() {
if (!this.state.username) {
return;
}
if (!this.state.password) {
return;
}
this.setState({
buttonDisabled: true
})
try {
console.log(this.state.username)
console.log(this.state.password)
const payLoad = {username: this.state.username, password: this.state.password};
let res = await fetch('/login', {
method: "POST",
mode: "cors",
headers: {
"Content-Type": "application.json",
"Access-Control-Allow-Origin":"*"
},
body: JSON.stringify(this.state )
});
let result = await res.json();
if (result && result.success) {
UserStore.isLoggedIn = true;
UserStore.username = result.username;
}
else if (result && result.success === false) {
this.resetForm();
alert(result.msg);
}
}
catch(e) {
console.log(e)
this.resetForm();
}
}
render() {
return (
<div>
Log in
<InputField
type='text'
placeholder='Username'
value={this.state.username ? this.state.username : ''}
onChange={ (val) => this.SetInputValue('username', val) }
/>
<InputField
type='password'
placeholder='Password'
value={this.state.password ? this.state.password : ''}
onChange={ (val) => this.SetInputValue('password', val) }
/>
<SubmitButton
text='Login'
disabled={this.state.buttonDisabled}
onClick={ () => this.doLogin() }
/>
</div>
)
}
}
export default LoginForm;
I can post the other components if necessary--don't want to overflow this post. From what I have troubleshooted, my frontend is fine (the payload is correct when examined in my browser's web tools). Any help on this would be greatly appreciated.

React. Can't acces API data on local 5000. Database from CSV file. Promise undefined response

I've been going crazy for a couple of days with an unresolved issue. Please help.
Working with a CSV database here. Creating own API. Small React App Fullstack MERN.
I'm trying to get to show all the employeees from my database.
I wrote the backend with express and have all the data now showing in json format on localhost:5000/employees
Also created a context on the front to deal with that data and reducer file for the functions.
Problem I have is I'm not beeing able to use the data on the ContextProvider file. ('EmployeesState')
Promise of my async function keeps giving me an undefined response. Tried both with fetch and axios but is not working.
Some of the code is from a previous project i did and it worked there so i 'm going crazy here. I can't seem to solve it. Please help.
BACKEND
db.js
const parse = require("csv-parse");
const fs = require("fs");
const employeesData = [];
const connectDB = () => {
fs.createReadStream(__dirname + "/employees1.txt")
.pipe(
parse({
delimiter: ",",
columns: true,
})
)
.on("data", (dataRow) => {
employeesData.push(dataRow);
})
.on("end", () => {
console.log(employeesData);
});
};
connectDB();
// console.log(connectDB());
module.exports = connectDB;
module.exports = employeesData;
server.js
var createError = require("http-errors");
var express = require("express");
const bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
const logger = require("morgan");
const cors = require("cors");
const connectDB = require("./config/db");
const employeesData = require("./config/db");
var path = require("path");
var app = express();
// const config = require("config");
//Connect DB
// connectDB();
let dataBase = employeesData;
console.log(employeesData);
app.use(cors());
// app.use(bodyParser.json()); //here
// Initial Middleware
//By doing this we can accepta data. Using the req.body
app.use(express.json({ extended: false }));
///Define Routes
app.use("/", require("./routes/index"));
app.use("/employees", require("./routes/employees"));
//Serve React in production
if (process.env.NODE_ENV === "production") {
//Set static folder (build folder)
app.use(express.static("client/build"));
app.get("*", (req, res) =>
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"))
);
}
// app.engine("html", require("ejs").renderFile);
app.set("view engine", "html");
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
employees.js
const express = require("express");
const router = express.Router();
const config = require("config");
const { check, validationResult } = require("express-validator");
const Employee = require("../models/EmployeeModel");
const employeesData = require("../config/db");
// router.get("/", function (req, res) {
// res.send({ employeesData });
// });
//#route GET api/employees
//#desc Get all users Employees
//#access Private
router.get("/", async (req, res) => {
try {
const employees = await employeesData;
res.json({ employees });
} catch (err) {
console.error(err.message);
res.status(500).send("Server error");
}
});
//#route POST api/employees
//#desc Add new Employee
//#access Private
router.post(
"/",
[
check("name", "Name is required").not().isEmpty(),
check("surname", "Surname is required").not().isEmpty(),
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { name, surname, adress, phone, email, birthdate } = req.body;
try {
const newEmployee = new Employee({
name,
surname,
adress,
phone,
email,
birthdate,
});
const employee = await newEmployee.save();
res.json(employee);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
}
);
//#route DELETE api/employee
//#desc Delete Employee
router.delete("/:id", async (req, res) => {
try {
let employee = await Employee.findById(req.params.id);
if (!employee) return res.status(404).json({ msg: "Employee not found" });
await Employee.findByIdAndRemove(req.params.id);
res.json({ msg: `Employee removed` });
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
module.exports = router;
FRONTEND
EmployeesState.js
import React, { useReducer, useState } from "react";
import axios from "axios";
import { v4 as uuid } from "uuid";
import EmployeesContext from "./employeesContext";
import employeesReducer from "./employeesReducer";
import {
ADD_EMPLOYEE,
DELETE_EMPLOYEE,
SET_CURRENT,
CLEAR_CURRENT,
UPDATE_EMPLOYEE,
FILTER_EMPLOYEES,
EMPLOYEE_ERROR,
CLEAR_FILTER,
GET_EMPLOYEES,
CLEAR_EMPLOYEES,
} from "../types";
const EmployeesState = (props) => {
const initialState = {
employees: [],
current: null,
filtered: null,
error: null,
loading: false,
};
const [state, dispatch] = useReducer(employeesReducer, initialState);
const [employees, setEmployees] = useState(initialState);
//Get Employees
// // gives me promise{<prending>} on console
const getEmployees = async () => {
try {
const res = axios.get("http://localhost:5000/employees");
dispatch({ type: GET_EMPLOYEES, payload: res });
} catch (err) {
dispatch({
type: EMPLOYEE_ERROR,
});
}
};
//trying with fetch. throwing me undefined on console
const callAPI = () => {
fetch("http://localhost:5000/employees")
.then((res) => res.json())
.then((res) =>
setEmployees({
...initialState,
loading: false,
employees: res,
})
);
};
//Add Employee
const addEmployee = async (employee) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
const res = await axios.post("/employees", employee, config);
dispatch({ type: ADD_EMPLOYEE, payload: res.data });
} catch (err) {
dispatch({
type: EMPLOYEE_ERROR,
payload: err.response.data.msg,
});
}
};
//Delete Employee
const deleteEmployee = async (id) => {
try {
await axios.delete(`/employees/${id}`);
dispatch({ type: DELETE_EMPLOYEE, payload: id });
} catch (err) {
dispatch({
type: EMPLOYEE_ERROR,
payload: err.response.msg,
});
}
};
//Update Employee
const updateEmployee = async (employee) => {
const config = {
headers: {
"Content-Type": "application/json",
},
};
try {
const res = await axios.put(
`/api/employees/${employee._id}`,
employee,
config
);
dispatch({ type: UPDATE_EMPLOYEE, payload: res.data });
} catch (err) {
dispatch({
type: EMPLOYEE_ERROR,
payload: err.response.msg,
});
}
dispatch({ type: UPDATE_EMPLOYEE, payload: employee });
};
//Clear Employees
const clearEmployees = () => {
dispatch({ type: CLEAR_EMPLOYEES });
};
//Set Current Employees
const setCurrent = (employee) => {
dispatch({ type: SET_CURRENT, payload: employee });
};
//Clear Current Employee
const clearCurrent = () => {
dispatch({ type: CLEAR_CURRENT });
};
//Filter Employees
const filterEmployees = (text) => {
dispatch({ type: FILTER_EMPLOYEES, payload: text });
};
//Clear Filter
const clearFilter = (text) => {
dispatch({ type: CLEAR_FILTER });
};
return (
<EmployeesContext.Provider
value={{
employees: state.employees,
current: state.current,
filtered: state.filtered,
error: state.error,
loading: state.loading,
callAPI,
getEmployees,
addEmployee,
deleteEmployee,
clearEmployees,
setCurrent,
clearCurrent,
updateEmployee,
filterEmployees,
clearFilter,
}}
>
{props.children}
</EmployeesContext.Provider>
);
};
export default EmployeesState;
// // gives me undefined on console
// const getEmployees = () => {
// axios
// .get("http://localhost:5000/employees")
// .then((res) => dispatch({ type: GET_EMPLOYEES, payload: res }))
// .catch((err) => {
// dispatch({
// type: EMPLOYEE_ERROR,
// });
// });
// };
Home.js
import React, { Fragment } from "react";
import Search from "../employees/Search";
import Employees from "../employees/Employees";
const Home = () => {
return (
<>
<Search />
<Employees />
</>
);
};
export default Home;
Employees.js
import React, { useContext, useEffect } from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import EmployeeItem from "./EmployeeItem";
import { v4 as uuidv4 } from "uuid";
import EmployeesContext from "../../contexts/employees/employeesContext";
import Spinner from "../layout/Spinner";
const Employees = () => {
const employeesContext = useContext(EmployeesContext);
const {
employees,
filtered,
getEmployees,
callAPI,
loading,
} = employeesContext;
useEffect(() => {
// callAPI();
getEmployees();
// eslint-disable-next-line
console.log(employees);
console.log(getEmployees());
console.log(callAPI());
}, []);
return (
<div>
<>
{[employees].map((employee) => (
<EmployeeItem key={uuidv4()} employee={employee} />
))}
</>
</div>
);
employeesReducer.js
import {
GET_EMPLOYEES,
ADD_EMPLOYEE,
DELETE_EMPLOYEE,
SET_CURRENT,
CLEAR_CURRENT,
UPDATE_EMPLOYEE,
FILTER_EMPLOYEES,
CLEAR_FILTER,
EMPLOYEE_ERROR,
CLEAR_EMPLOYEES,
} from "../types";
export default (state, action) => {
switch (action.type) {
case GET_EMPLOYEES:
return {
...state,
employees: action.payload,
loading: false,
};
case ADD_EMPLOYEE:
return {
...state,
employee: [action.payload, ...state.employees],
loading: false,
};
case UPDATE_EMPLOYEE:
return {
...state,
employees: state.employees.map((employee) =>
employee._id === action.payload._id ? action.payload : employee
),
loading: false,
};
case DELETE_EMPLOYEE:
return {
...state,
employees: state.employees.filter(
(employee) => employee._id !== action.payload
),
loading: false,
};
case CLEAR_EMPLOYEES:
return {
...state,
employees: null,
filtered: null,
error: null,
current: null,
};
case SET_CURRENT:
return {
...state,
current: action.payload,
};
case CLEAR_CURRENT:
return {
...state,
current: null,
};
case FILTER_EMPLOYEES:
return {
...state,
filtered: state.employees.filter((employee) => {
const regex = new RegExp(`${action.payload}`, "gi");
return employee.name.match(regex) || employee.email.match(regex);
}),
};
case CLEAR_FILTER:
return {
...state,
filtered: null,
};
case EMPLOYEE_ERROR:
return {
...state,
error: action.payload,
};
default:
return state;
}
};
You need to await for the response
const res = await axios.get("http://localhost:5000/employees");
dispatch({ type: GET_EMPLOYEES, payload: res });
or
axios.get("http://localhost:5000/employees")
.then(res => {
dispatch({ type: GET_EMPLOYEES, payload: res });
})

Send a message from Server side to React front (NodeJS)

Im currently trying to send a message from my server side and display it in my react front end.
I have tried everything to display the message I use with res.send() but the react fails to receive it can anyone help me point out what I am doing wrong here?
Sample of the front end:
import React, {Component} from 'react';
import axios from 'axios';
import Tabs from 'react-bootstrap/Tabs';
import Tab from 'react-bootstrap/Tab';
export default class CreateFile extends Component {
constructor(props) {
super(props);
this.onChangeFileDescription = this.onChangeFileDescription.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
file_description: '',
};
this.handleSelect = this.handleSelect.bind(this);
axios
.get("http://localhost:4000/api/isloggedin")
.then(res => {
if (!res.data) {
return this.setState({isloggedin: false});
}
});
}
onChangeFileDescription(e) {
this.setState({
file_description: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
console.log(`Form submitted:`);
console.log(`File Description: ${this.state.file_description}`);
const newFile = {
file_description: this.state.file_description,
}
axios.post('http://localhost:4000/files/add', newFile)
.then(res => console.log(res.data));
this.setState({
file_description: '',
})
}
render() {
return this.state.isloggedin ? (
<div style={{marginTop: 20}}>
<h3>Upload a New File</h3>
<Tabs
id="controlled-tab-example"
activeKey={this.state.key}
onSelect={key => this.setState({key})}
>
<Tab eventKey="audio" title="Audio">
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>File Description: </label>
<input type="text"
className="form-control"
value={this.state.file_description}
onChange={this.onChangeFileDescription}
/>
</div>
</Tabs>
</div>
) : (
<h3>Please login</h3>
);
}
}
This is the server side:
Im checking if the submitted form is empty and if it is sending a error back asking users to fill the required field.
const express = require('express');
const bodyParser = require('body-parser');
const fileRoutes = express.Router();
const File = require("../models/fileHandler");
module.exports = function(app) {
app.use(bodyParser.json());
fileRoutes.route('/').get(function (req, res) {
File.find(function (err, files) {
if (err) {
console.log(err);
} else {
res.json(files);
}
});
});
fileRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
File.findById(id, function (err, file) {
res.json(file);
});
});
fileRoutes.route('/add').post(function (req, res) {
console.log(req.body.file_description);
if (req.body.file_description === ""){
console.log("its empty!");
var result = {"data" :"hello everybody !"}
res.status(200).json({'description': 'description is needed'});
return res.send(result);
}
let file = new File(req.body);
file.save()
.then(file => {
res.status(200).json({'file': 'file added successfully'});
})
.catch(err => {
res.status(400).send('adding new file failed');
});
});
fileRoutes.route('/update/:id').post(function (req, res) {
File.findById(req.params.id, function (err, file) {
if (!file)
res.status(404).send('data is not found');
else
file.file_description = req.body.file_description;
file.file_size = req.body.file_size;
file.file_duration = req.body.file_duration;
file.file_artist = req.body.file_artist;
file.file_bitrate = req.body.file_bitrate;
file.file_codec = req.body.file_codec;
file.file_audioChannels = req.body.file_audioChannels;
file.file_dimensions = req.body.file_dimensions;
file.file_tag = req.body.file_tag;
file.file_colorProfile = req.body.file_colorProfile;
file.file_extension = req.body.file_extension;
file.file_employeeResponsible = req.body.file_employeeResponsible;
file.file_editActive = req.body.file_editActive;
file.file_completed = req.body.file_completed;
file.save().then(file => {
res.json('File updated');
})
.catch(err => {
res.status(400).send("Update not possible");
});
});
});
app.use('/files', fileRoutes);
};
Ok after some digging I managed to solve this issue.
I thought i posted here in case anyone had a similar problem.
So what I did was to check everything with express validator and if there was any problem to send it to the react front end.
And in react front end if the there is any problem received regarding that specific field it will display it on top of the input field.
hope this helps.
{this.state.errors &&
this.state.errors.file_description && <p>{this.state.errors.file_description.msg}
And the complete snippet of the react front end.
import React, {Component} from 'react';
import axios from 'axios';
import Tabs from 'react-bootstrap/Tabs';
import Tab from 'react-bootstrap/Tab';
export default class CreateFile extends Component {
constructor(props) {
super(props);
this.onChangeFileDescription = this.onChangeFileDescription.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
file_description: ''
};
this.handleSelect = this.handleSelect.bind(this);
axios
.get("http://localhost:4000/api/isloggedin")
.then(res => {
if (!res.data) {
return this.setState({isloggedin: false});
}
});
}
onChangeFileDescription(e) {
this.setState({
file_description: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
console.log(`Form submitted:`);
console.log(`File Description: ${this.state.file_description}`);
const newFile = {
file_description: this.state.file_description
}
axios.post('http://localhost:4000/files/add', newFile)
.then(result => {
if (result.data.errors) {
return this.setState(result.data);
}
return this.setState({
userdata: result.data,
errors: null,
success: true
});
});
this.setState({
file_description: ''
})
}
render() {
return this.state.isloggedin ? (
<div style={{marginTop: 20}}>
<h3>Upload a New File</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>File Description: </label>
<input type="text"
className="form-control"
value={this.state.file_description}
onChange={this.onChangeFileDescription}/>
{this.state.errors &&
this.state.errors.file_description && <p>{this.state.errors.file_description.msg}</p>}
</div>
<label className="form-check-label">Yes</label>
</div>
</div>
<div className="form-group">
<input type="submit" value="Upload File" className="btn btn-primary"/>
</div>
</form>
</Tab>
</Tabs>
</div>
) : (
<h3>Please login</h3>
);
}
}
for the backend I have also tweaked it so if there is any problem it will post that back to the react front end validating with Express validator and using the normal route and post methods.
const express = require('express');
var { check, validationResult } = require("express-validator/check");
const bodyParser = require('body-parser');
const fileRoutes = express.Router();
const File = require("../models/fileHandler");
module.exports = function(app) {
const fileValidation = [
check("file_description")
.not()
.isEmpty()
.withMessage("Description required"),
];
app.use(bodyParser.json());
fileRoutes.route('/').get(function (req, res) {
File.find(function (err, files) {
if (err) {
console.log(err);
} else {
res.json(files);
}
});
});
fileRoutes.route('/:id').get(function (req, res) {
let id = req.params.id;
File.findById(id, function (err, file) {
res.json(file);
});
});
fileRoutes.route('/add').post(fileValidation, function (req, res) {
var errors = validationResult(req);
if (!errors.isEmpty()) {
return res.send({ errors: errors.mapped() });
}else{
console.log("its empty!");
let file = new File(req.body);
file.save()
.then(file => {
res.status(200).json({'file': 'file added successfully'});
})
.catch(err => res.send(err));
}
});
fileRoutes.route('/update/:id').post(function (req, res) {
File.findById(req.params.id, function (err, file) {
if (!file)
res.status(404).send('data is not found');
else
file.file_description = req.body.file_description;
file.save().then(file => {
res.json('File updated');
})
.catch(err => {
res.status(400).send("Update not possible");
});
});
});
app.use('/files', fileRoutes);
};

Categories