Why is useEffect(()={...},[]) not being called on component load? - reactjs

There are numerous questions relating to useEffect() and running on initial page render. I am experiencing the same problem even after making sure my code is correct regarding parameters passed to useEffect.
useEffect(() => {
const token = Cookies.get('token');
setRole(Cookies.get('role'));
fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": role,
"language": "en",
"api_token": token
})
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData)
}
})
}, [])
For some reason this doesn't seem to be called after the component mounts.
Here is the full page code:
import Header from "../../../components/header"
import { useRouter } from "next/router"
import Link from 'next/link'
import Pagination from "../../../components/datatable/pagination"
import Cookies from "js-cookie"
import { parseCookies } from "nookies"
import { useState, useEffect } from "react"
import { Modal, Button } from "react-bootstrap";
import UserSidebar from "../../../components/user_sidebar"
import TabButtonUser from "../../../components/tabbuttonuser"
import Address from "../../../components/address"
const AdminUsers = ({ data }) => {
const router = useRouter()
// const limit = 3
// const lastPage = Math.ceil(totalPage / limit)
// console.log(data)
// console.log(listUsers)
/**
* Manage states
*/
const [show, setShow] = useState(false);
const [isEdit, setIsEdit] = useState(false);
const [fullNname, setFullName] = useState("");
const [emailID, setEmailID] = useState("");
const [country_code, setCountry_code] = useState("");
const [phone_number, setPhone_number] = useState("");
const [company_access, setCompany_access] = useState("");
const [isActive, setActive] = useState("");
const [userID, setUserId] = useState("");
const [role, setRole] = useState("");
const [thisUserData, setThisUser] = useState({})
useEffect(() => {
const token = Cookies.get('token');
setRole(Cookies.get('role'));
fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": role,
"language": "en",
"api_token": token
})
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData)
}
})
}, [])
/**
* Clear values
*/
const handleClose = () => {
setShow(false)
setIsEdit(false);
setUserId("")
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
};
const handleShow = () => setShow(true);
/**
* Add User
* #param {*} e
* #returns
*/
const addUser = async (e) => {
e.preventDefault();
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const resUser = await fetch(`${process.env.API_URL}/user/create-sub-admin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"full_name": fullNname,
"email_id": emailID,
"country_code": "+1",
"phone_number": phone_number,
"api_token": token
})
})
const res2User = await resUser.json();
console.log(res2User);
if (res2User.status_code == 200) {
handleClose();
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
}
}
/**
* Get user details basis of user id for edit purpose
* #param {*} id
* #returns
*/
const getUser = async (id) => {
// e.preventDefault();
setIsEdit(true);
setShow(true);
setUserId(id)
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const userData = await fetch(`${process.env.API_URL}/user/user-details`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": id,
"language": "en",
"api_token": token
})
})
const userData2 = await userData.json();
console.log(userData2);
if (userData2.status_code == 200) {
// handleClose();
setFullName(userData2?.data?.full_name);
setEmailID(userData2?.data?.email_id);
setCountry_code(userData2?.data?.phone_number?.country_code);
setPhone_number(userData2?.data?.phone_number?.phone_number);
}
}
/**
* Remove user
* Api is pending
* #param {*} id
*/
const removeUser = async (id) => {
}
/**
*Update User
*
* #return {*}
*/
const updateUser = async () => {
// e.preventDefault();
const token = Cookies.get('token');
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const resUser = await fetch(`${process.env.API_URL}/user/update-user`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"user_id": userID,
"full_name": fullNname,
"email_id": emailID,
"country_code": "+1",
"phone_number": phone_number,
"api_token": token,
"is_active": isActive
})
})
const res2User = await resUser.json();
console.log(res2User);
if (res2User.status_code == 200) {
setFullName("");
setEmailID("");
setCountry_code("");
setPhone_number("");
setIsEdit(false);
setShow(false);
setUserId("")
}
}
const address = {
"address_line": "",
"city_name": "",
"state_name": "",
"zip_code": ""
}
return (
<>
<Header />
<div className="container">
<div className="row">
<div className="col-3">
<UserSidebar data={thisUserData} />
</div>
<div className="col">
<div className="sidebarwrap">
{/* <TabButtonUser id={data?._id} /> */}
<h3 className="acc_title">My Company</h3>
<h2 className="login_name">Alliance Credit</h2>
<div className="acc_email">
email#company.com
</div>
<div className="acc_phone">+1234567890</div>
<Address address={address} />
<div className="ac_left acc_title">All Team Members</div>
<div className="ac_right">
{role.indexOf('admin') > -1 ?
<button className="btn btnedit" onClick={handleShow}>Add Sub-Admin</button>
: ''}
</div>
<div className="clearfix"></div>
<div className="listing">
<table id="example" className="table table-striped">
<thead>
<tr>
<th><div>Sr. Number</div></th>
<th><div>User Name</div></th>
<th><div>Date Added</div></th>
<th><div>Email</div></th>
<th><div>Actions</div></th>
</tr>
</thead>
<tbody>
{data?.map((item, index) => (
<tr key={index}>
<td>{index + 1}</td>
<td>{item.full_name}</td>
<td>{item.date_added}</td>
<td>{item.email_id}</td>
<td>
<>
<button className="btn viewmore" onClick={() => getUser(item._id)}>Edit User</button>
</>
</td>
</tr>
))}
</tbody>
</table>
{/* <Pagination page={page} totalPage={totalPage} lastPage={lastPage} /> */}
</div>
</div>
</div>
</div>
</div>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>{isEdit == false
? "Add Sub-Admin"
: "Edit Sub-Admin"
}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="popupform">
<form method="POST">
<div className="row">
<div className="col">
<label htmlFor="fullname" className="form-label">Full Name</label>
<input className="form-control" name="fullname" type="text" id="fullname" value={fullNname} onChange={(e) => setFullName(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
<label htmlFor="emailID" className="form-label">Email</label>
<input className="form-control" name="emailID" type="text" id="emailID" value={emailID} onChange={(e) => setEmailID(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
<label htmlFor="phone_number" className="form-label">Phone Number</label>
<input className="form-control" name="phone_number" type="text" id="phone_number" value={phone_number} onChange={(e) => setPhone_number(e.target.value)} />
</div>
</div>
<div className="row">
<div className="col">
{isEdit ? (
<>
<label htmlFor="phone_number" className="form-label">Active status</label>
<select className="form-control form-select" onChange={(e) => setActive(e.target.value)}>
<option value="0">Active</option>
<option value="1">Deactivate</option>
</select>
</>
) : ''
}
</div>
</div>
<div>
<input className="form-control" name="userID" type="hidden" id="company_logo_en" value={userID} />
</div>
</form>
</div>
</Modal.Body>
<Modal.Footer>
{isEdit == false
? <>
<Button variant="secondary" className="btn btnedit" onClick={handleClose}>Cancel</Button>
<Button variant="primary" onClick={addUser}>Add User</Button>
</>
:
<>
<Button variant="primary" className="btn btnremove" onClick={removeUser}>Remove User</Button>
<Button variant="primary" className="btn btnedit">Reset User</Button>
<Button variant="primary" onClick={updateUser}>Save</Button>
</>
}
</Modal.Footer>
</Modal>
</>
)
}
/**
*
*
* #export
* #param {*} { query: { page = 1, data = null, totalPage = 10 } }
* #return {*}
*/
// export async function getServerSideProps({ query: { page = 1, data = null, totalPage = 10 } }) {
export async function getServerSideProps(ctx) {
// const start = +page === 1 ? 0 : (+page + 1)
// const { locale, locales, defaultLocale, asPath } = useRouter();
const { token } = parseCookies(ctx)
if (!token) {
return {
redirect: {
destination: '/',
permanent: false,
},
}
}
const res = await fetch(`${process.env.API_URL}/user/list-sub-admin`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"language": 'en',
"api_token": token,
})
})
const data = await res.json()
/**
* limit, start, search item
*/
return {
props: {
data: data?.data || [],
}
}
}
export default AdminUsers
I am sure it is something simple that I've missed (it usually is) but I can't seem to spot it.
Thanks.

It's not clear for me this problem, but I try to write what I see: you have defined useEffect with the fetch without deps. In that fetch you use role state which is initialized to empty string in the first time. You set the role using setRole in the same useEffect but this has no effect for the precedent reasons.
My suggestion is to remove role state and redefine useEffect like this:
useEffect(() => {
const token = Cookies.get('token');
const role = Cookies.get('role');
fetch(`${process.env.API_URL}/user/user-details`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
user_id: role,
language: 'en',
api_token: token,
}),
})
.then((user) => user.json())
.then((thisUserData) => {
if (thisUserData.status_code == 200) {
setThisUser(thisUserData);
}
});
}, []);

React's state setters are asynchronous(see here), so when you use 'role' right after 'setRole', role is still an empty string. Thus the fetch returns nothing.

The answer may not be directly related to the question itself, but it may be useful to an another developer who is searching for an answer.
In my case I had two components and change rendering them when a button was clicked on the interface and I had accidentally put [] in dependencies, I fixed it by removing it.
Before,
useEffect(() => {
// your function
},[]);
After
useEffect(() => {
// your function
});

Related

I want to send text entered in modal in React.js to Backend

I am using React.js to create the front-end side of a web application that can control home appliances.
What I want to achieve is
I want to send the text entered in the modal to Backend.
At that time, I want to prevent the screen reload.
Issue is
When I put the text in the modal and press the Submit button, the page reload happens and I can't see what was sent in the console.
Please see the video below for details.
https://youtu.be/_ppCNBTBIvc
AddRoomModal.js
import Modal from 'react-bootstrap/Modal';
const cookies = new Cookies();
const AddRoomModal = (props) => {
const [room_name, setRoomName] = useState("");
const addRoom = (e) => {
setRoomName(e.target.value);
}
const clickSubmit = (e) => {
AddRoom(e.target.value);
}
const building_state = useSelector(state => state.building_state.building_state);
console.log(building_state);
const url_forgetroomname = {
"condo": "aaa.com",
"office": "bbb.com",
"house": "ccc.com"
}[building_state]
const AddRoom = async(data) => {
console.log("Body sent to server", {
home_rooms: room_name,
})
await axios.post(url_forgetroomname,
{
home_rooms: room_name,
},
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${cookies.get('accesstoken')}`
},
})
.then(result => {
alert('Succeded add room!');
console.log('Succeded add room!');
})
.catch(err => {
alert('Missed add room!');
console.log(err);
console.log('Missed add room!');
});
}
const getRoomName = async(data) => {
await axios.get(url_forgetroomname,
{
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${cookies.get('accesstoken')}`
},
})
.then(result => {
console.log(result.data)
setRoomName(result.data.home_rooms);
})
.catch(err => {
console.log(err);
});
}
return (
<>
<Modal show={props.show}>
<Modal.Body className="light_modal_body" >
<div className="light_modal_body">
<div className="range-container col-12">
</div>
<h3>Add Room</h3>
<form>
<input type="text" onChange={addRoom} value={room_name}/>
<div className="done_button">
<button className='btn btn-block btn-primary' type="submit" onClick={clickSubmit}>
OK
</button>
</div>
</form>
<div className="done_button">
<button onClick={props.handleHide} className='btn btn-block btn-danger'>Cancel</button>
</div>
</div>
</Modal.Body>
</Modal>
</>
);
}
export default AddRoomModal;
HeaderForSettingGetRoomName.js
import AddRoomModal from '../AddRoomModal';
const cookies = new Cookies();
const HeaderForSettingGetRoomName = (props) => {
const isLoggedInOn = useSelector(state => state.user.isLoggedIn);
// modal
const [show, setShow] = useState();
// Show Modal
const handleShow = () => {
setShow(true);
}
// Hide modal
const handleHide = () => {
setShow(false);
}
const building_state = useSelector(state => state.building_state.building_state);
console.log(building_state);
return (
<div>
<AddRoomModal
show={show} handleHide={handleHide}
/>
<div className="header">
<Link to={`/setting`} className=""> <img className="header_menu_back_leftside" src={ic_back} alt="" />
</Link>
<img className="header_logo" src={logo_image} />
<img className="ic_add_white" src={ic_add_white} onClick={handleShow}/>
</div>
</div>
);
}
export default HeaderForSettingGetRoomName;
You can disable the default form behaviour (submitting the form) by calling preventDefault on the submit event
const clickSubmit = (e) => {
e.preventDefault();
AddRoom(e.target.value);
}

How to parse object to another component using fetch

I need to be able to parse obj to another component called GuestForm.
However when i try to set obj.first_name i can see in the console that the the obj.first_name value is empty.
On top of having the object empty i would like to parse it to the component.
import React, { Component, useState, useEffect } from 'react';
import GuestForm from '../../components/Guests/GuestForm.js';
import { useParams } from 'react-router-dom';
import axios from "axios";
function Edit() {
const { id } = useParams();
const [mode, setMode] = useState('edit');
const [successMessage, setsuccessMessage] = useState('The guest has been edited successfully!');
const [action, setAction] = useState('/guests/edit');
const obj = {first_name: '', last_name: '', email: '', password: ''};
const headers = {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Origin": "*",
"Accept": "application/json"
}
const res = fetch(process.env.REACT_APP_API_URL + action, {
method: 'POST',
headers: headers,
body: JSON.stringify({data: {id: id}}),
})
.then((response) => response.json())
.then((responseJson) => {
//return responseJson.json.guest;
obj.first_name = responseJson.json.guest.first_name;
})
.catch((error) => {
console.error(error);
});
console.log(obj); // Empty value for first name here...
return (
<>
<div className="container">
<GuestForm mode={mode} successMessage={successMessage} obj={obj} action={action} />
</div>
</>
);
}
export default Edit;
GuestForm
Here the component GuestForm which should display first name value in the field
import React, { Component, useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useHistory } from 'react-router-dom';
// react-bootstrap components
import {
Button,
Card,
Form,
Row,
Col,
} from "react-bootstrap";
import axios from "axios";
import { toast } from 'react-toastify';
function GuestForm({mode, successMessage, obj, action}) {
const history = useHistory();
const [details, setDetails] = useState([]);
const [loading, setLoading] = useState(false);
const [first_name, setFirstName] = useState(obj.first_name);
const [last_name, setLastName] = useState(obj.last_name);
const [email, setEmail] = useState(obj.email);
const [password, setPassword] = useState(obj.password);
const handleSave = e => {
e.preventDefault();
setLoading(true);
axios({
method: "POST",
url: process.env.REACT_APP_API_URL + action,
headers: { 'Content-Type': 'application/json;charset=UTF-8', "Access-Control-Allow-Origin": "*", "Accept": "application/json" },
data: {
data: obj
}
}).then(result => {
if(result.data.json.error == false) {
toast(successMessage, {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
history.push('/dashboard/guests');
}
setDetails(result.data.json);
setLoading(false);
});
};
return (
<>
<div className="container">
<div class="row">
<div class="col-lg-12">
<h1 className="mt-0 mb-4 green-color">{mode == 'edit'? <span>Edit</span>: 'New' } Guest</h1>
</div>
</div>
<Form onSubmit={handleSave} autoComplete="off">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 mt-2">
<Form.Group>
<label htmlFor="exampleInputEmail1">
Email Address
</label>
<Form.Control
value={email}
onChange={e => setEmail(e.target.value)}
type="email"
autoComplete="off"
></Form.Control>
</Form.Group>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 mt-2">
<Form.Group>
<label>Password</label>
<Form.Control
value={password}
onChange={e => setPassword(e.target.value)}
type="password"
autoComplete="new-password"
></Form.Control>
</Form.Group>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 mt-2">
<Form.Group>
<label>First Name</label>
<Form.Control
value={first_name}
onChange={e => setFirstName(e.target.value)}
type="text"
autoComplete="off"
></Form.Control>
</Form.Group>
</div>
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 mt-2">
<Form.Group>
<label>Last Name</label>
<Form.Control
value={last_name}
onChange={e => setLastName(e.target.value)}
type="text"
autoComplete="off"
></Form.Control>
</Form.Group>
</div>
</div>
{(details.guest && details.error ) && <div className="error-message mt-4 mb-1">{details.message}</div>}
<Button
className="btn-fill pull-right mt-3"
type="submit"
variant="info"
disabled={loading}
>
{loading && <span>{mode == 'edit'? <span>SAVE CHANGES</span>: 'ADD' }...</span>}
{!loading && <span>{mode == 'edit'? <span>SAVE CHANGES</span>: 'ADD' }</span>}
</Button>
<div className="clearfix"></div>
</Form>
</div>
</>
);
}
export default GuestForm;
The reason your console.log is showing up as empty is because you are setting the value of obj.first_name in an asynchronous callback, but the actual logging line will be executed synchronously before that asynchronous callback is called. If you were to instead add another .then to the chain and do the console.log in there, you would see the updated value. Here's a snippet that demonstrates what I mean:
const obj = { a: 'b' };
Promise.resolve()
.then(() => {
obj.a = 'c';
})
.then(() => {
console.log('async:', obj);
});
console.log('sync:', obj);
If you want to send this value to GuestForm, you'll have to use a state variable that will be updated once the fetch call finishes. You also want to wrap this fetch call in a useEffect, so that calling setObj doesn't result in an endless loop (the fetch call causes the state update, which then causes the component to be re-rendered, which causes the fetch call to rerun, and so on). Something like:
import React, { Component, useState, useEffect } from 'react';
import GuestForm from '../../components/Guests/GuestForm.js';
import { useParams } from 'react-router-dom';
import axios from "axios";
function Edit() {
const { id } = useParams();
const [mode, setMode] = useState('edit');
const [successMessage, setsuccessMessage] = useState('The guest has been edited successfully!');
const [action, setAction] = useState('/guests/edit');
const [obj, setObj] = useState({first_name: '', last_name: '', email: '', password: ''});
const headers = {
'Content-Type': 'application/json;charset=UTF-8',
"Access-Control-Allow-Origin": "*",
"Accept": "application/json"
}
useEffect(() => {
const res = fetch(process.env.REACT_APP_API_URL + action, {
method: 'POST',
headers: headers,
body: JSON.stringify({data: {id: id}}),
})
.then((response) => response.json())
.then((responseJson) => {
//return responseJson.json.guest;
const newObj = { ...obj, first_name:
responseJson.json.guest.first_name };
setObj(newObj);
})
.catch((error) => {
console.error(error);
});
}, []);
console.log(obj); // This will now show the updated value (but will still have the default value on the initial render)
return (
<>
<div className="container">
<GuestForm mode={mode} successMessage={successMessage} obj={obj} action={action} />
</div>
</>
);
}
export default Edit;
To use the updated value in GuestForm, you need to make sure your state variable is updated when the passed in prop is updated. This is best achieved with a useEffect. Add this to your GuestForm component
useEffect(() => {
setFirstName(obj.first_name);
}, [obj]);
This is necessary because you're duplicating the prop value with state variables in the child component. A more common pattern would be to pass both obj and setObj as props to GuestForm so that in the child you can modify the parent's state variable directly without creating a copy

Unable to update product using react but can update using postman

I am new to react development. I am using redux to update my product. I had succeeded in updating the product from postman but I couldn't update from the admin panel. I think there is an issue in the front end as API is tested using postman and the backend is working. Kindly help me.
My Product component
import { Link } from "react-router-dom";
import "./Product.css";
import { useLocation } from "react-router-dom";
import axios from "axios";
import { Publish } from '#mui/icons-material';
import { useSelector } from "react-redux";
import { updateProduct } from "../../Redux/apiCalls";
import { useDispatch } from "react-redux";
import { useState } from "react";
const Product = () => {
const location=useLocation();
const productId=location.pathname.split("/")[2];
const product=useSelector(state=>state.product.products.find(product=>product._id===productId))
const dispatch=useDispatch();
console.log(productId);
// const [title, setTitle]=useState("");
// const [desc, setDesc]=useState("");
// const [price, setPrice]=useState("");
// const [inStock, setInStock]=useState("");
const [inputs, setInputs]=useState({})
const handleChange=(e)=>{
setInputs((prev) => {
return { ...prev, [e.target.name]: e.target.value };
});
}
console.log(inputs);
const handleUpdate=async()=>{
await updateProduct(productId, inputs , dispatch)
// await axios.put('http://localhost:5000/api/products/`$productId`', inputs, productId)
// .then(response=>console.log(response.data))
}
return ( <>
<div className="product">
<div className="productTitleContainer">
<h1 className="productTitle">Product</h1>
<Link to="/newproduct">
<button className="productAddButton">Create</button>
</Link>
</div>
<div className="productTop">
<div className="productTopRight">
<div className="productInfoTop">
{/* <img src={product.img} alt="" className="productInfoImg" /> */}
<span className="productName">Product Name</span>
</div>
<div className="productInfoBottom">
<div className="productInfoItem">
<span className="productInfoKey">id:</span>
<span className="productInfoValue">{product._id}</span>
</div>
<div className="productInfoItem">
<span className="productInfoKey">sales:</span>
<span className="productInfoValue">5123</span>
</div>
<div className="productInfoItem">
<span className="productInfoKey">Price</span>
<span className="productInfoValue">{product.price}</span>
</div>
<div className="productInfoItem">
<span className="productInfoKey">in stock:</span>
<span className="productInfoValue">{product.inStock}</span>
</div>
</div>
</div>
</div>
<div className="productBottom">
<form className="productForm">
<div className="productFormLeft">
<label>Product Name</label>
<input type="text" placeholder={product.title} name="title" onChange={handleChange} />
<label>Product Description</label>
<input type="text" placeholder={product.desc} name="desc" onChange={handleChange} />
<label>Product Price</label>
<input type="text" placeholder={product.price} name="price" onChange={handleChange}/>
<label>In Stock</label>
<select name="inStock" id="idStock"
onChange={handleChange}
>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</div>
<div className="productFormRight">
<div className="productUpload">
<img src={product.img} alt="" className="productUploadImg"
/>
<label for="file">
<Publish/>
</label>
<input type="file" id="file" style={{display:"none"}} />
</div>
<button className="productButton" onClick={(e)=>handleUpdate(e.preventDefault())}>Update</button>
</div>
</form>
</div>
</div>
</> );
}
export default Product;
My Update component in Redux
export const updateProduct = async (id, product, dispatch) => {
dispatch(updateProductStart());
try {
const res = await userRequest.put(`/products/${id}`);
dispatch(updateProductSuccess({ id, product }));
} catch (err) {
dispatch(updateProductFailure());
}
};
updateProductStart: (state) => {
state.isFetching = true;
state.error = false;
},
updateProductSuccess: (state, action) => {
state.isFetching = false;
state.products[
state.products.findIndex((item) => item._id === action.payload.id)
] = action.payload.product;
},
updateProductFailure: (state) => {
state.isFetching = false;
state.error = true;
},
My API
import { ConstructionOutlined } from "#mui/icons-material";
import axios from "axios";
const BASE_URL = "http://localhost:5000/api/";
const user = JSON.parse(localStorage.getItem("persist:root"))?.user;
const currentUser = user && JSON.parse(user).currentUser;
const TOKEN = currentUser?.accessToken;
// const TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root")).user).currentUser.accessToken;
export const publicRequest = axios.create({
baseURL: BASE_URL,
});
export const userRequest = axios.create({
baseURL: BASE_URL,
headers: { token: `Bearer ${TOKEN}` },
});
My routes
router.put("/:id", verifyTokenAndAdmin, async (req, res) => {
try {
const updatedProduct = await Product.findByIdAndUpdate(
req.params.id,
{
$set: req.body,
},
{ new: true }
);
res.status(200).json(updatedProduct)
} catch (err) {
console.log("Can't update")
}
});
Model
const mongoose = require("mongoose");
const ProductSchema = new mongoose.Schema(
{
title: { type: String, required: true, unique: true },
desc: { type: String, required: true },
img: { type: String},
categories: { type: Array },
size: { type: Array },
color: { type: Array },
price: { type: Number, required: true },
inStock: { type: Boolean, default: true },
},
{ timestamps: true }
);
module.exports = mongoose.model("Product", ProductSchema);
Browsers won't allow cross origin requests if backend doesn't send response with header
Access-Control-Allow-Origin: <current domain name>
.
So at backend we need to send response with header Access-Control-Allow-Origin: localhost:3000
-> In express project:
Run
npm install cors
Change express initialization like this
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
This would add a header Access-Control-Allow-Origin: * to each response handled. This header says allow requests from browser within any website
Check more at
https://expressjs.com/en/resources/middleware/cors.html
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

action is not dispatching in react-redux

I have a form that collect data about today's expenditure and total users(as attendances) and then submit it using redux dispatch via action addExpenses(). But it douse not run. It seem that it is not counting if it is present or not.
function TodayExpenses() {
const dispatch = useDispatch()
const navigate = useNavigate()
useEffect(() => {
dispatch(getAttendance());
}, [date, getAttendanceObj, dispatch, addExpenses])
const [todayExpenses, setTodayExpenses] = useState(0)
const { attendance: getAttendanceObj, error: getAttendanceError, loading: getAttendanceLoading } = useSelector(state => state.getAttendance)
const { success } = useSelector(state => state.addExpenses)
const submitHandler = (e) => {
e.preventDefault();
let expenses = {
date: date,
total_attendances: count,
expenses_per_day: todayExpenses,
expenses_per_attendance: expensePerAttendance,
}
dispatch(addExpenses(expenses)) // Here be the dragons
console.log(todayExpenses)
}
const today = new Date().toISOString().substr(0, 10);
const [date, setDate] = useState(today)
const count = counter(getAttendanceObj, date)
const expensePerAttendance = (todayExpenses / count).toFixed(2);
return (
<div className="container">
<div class="h1 text-center text-dark" id="pageHeaderTitle">
Enter <input type="date" id="date" value={date} onChange={(e) => setDate(e.target.value)} max={today} />'s Expenses
</div>
<div className="row">
<div className="col-md-6 mx-auto">
<div className="card card-body">
<form onSubmit={submitHandler}>
<label htmlFor="name">Today's Expenses:</label>
<input
type="number"
className="form-group"
id="name"
placeholder="Enter value"
value={todayExpenses}
onChange={(e) => setTodayExpenses(e.target.value)}
/>
<ul class="list-group list-group-flush">
<label class="list-group-item card-header">Total Attendances</label>
<li class="list-group-item">{count}</li>
<label class="list-group-item card-header">Expense Per Attendance</label>
<li class="list-group-item">{expensePerAttendance}</li>
</ul>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
</div>
</div>
</div>
</div>
);
}
export default TodayExpenses;
What I have tried so far
What not? I tried console.log()even inside action but it working just above the required script ( I mean where the action have submit the data) .
if wanna ask here is action
export const addExpenses = (expenses) => async (getState, dispatch) => {
try {
dispatch({
type: ADD_EXPENSES_REQUEST
})
console.log("data:", dispatch({
type: ADD_EXPENSES_SUCCESS
}))
const { userLogin: { userInfo } } = getState();
const config = {
headers: {
'Content-type': 'application/json',
// 'Authorization': `JWT ${userInfo.token}`
}
}
const { data } = await axios.post(
'/api/expenses/post/',
expenses,
config
)
dispatch({
type: ADD_EXPENSES_SUCCESS,
payload: data
})
} catch (error) {
dispatch({
type: ADD_EXPENSES_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.response,
})
}
}
The dilemma is that I have copied it from other actions where it worked . I have also tried posting date using data manually using ThunderClient extention.(it is like insomnia or postman ) which mean there is no problem on the backend side.
Your thunk arguments are backwards. It should be (dispatch, getState)
export const addExpenses = (expenses) => async (dispatch, getState) => {

TypeError: formData.set is not a function

Hii i am getting an error when i am trying to filling a value in the form then getting error like "form data is not a function" dont know whats going on wrong please help as soon as possible
error img https://ibb.co/xMy002L
addmovie.js
here is my addmovie form where i wrote my whole logic
import React,{useState} from 'react';
import Navbar from '../pages/Navbar';
import Footer from '../pages/Footer';
import {Link} from 'react-router-dom';
import {isAuthenticated} from '../Auth/index';
import {addMovie} from '../Admin/adminapicall';
const AddMovie = () => {
const {user,token} = isAuthenticated();
const [values,setValues] = useState({
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
error:'',
addedMovie:'',
getRedirect:false,
formData:''
})
const {movie_name,actor,country_of_origin,duration,director,photo,loading,error,addedMovie,getRedirect,formData} = values;
const handleChange = name => event => {
const value = name === "photo" ? event.target.files[0] : event.target.value
formData.set(name,value);
setValues({...values,[name]:value})
};
const onSubmit = (e) => {
e.preventDefault();
setValues({...values,error:'',loading:true})
addMovie(user._id,token,formData).then(data =>{
if(data.error){
setValues({...values,error:data.error})
}else{
setValues({
...values,
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
addedMovie: data.movie_name
})
}
})
}
const successMessage = () => (
<div className='alert alert-success mt-3'
style={{display : addedMovie ? '' : 'none'}}>
<h4>{addedMovie} added successfully</h4>
</div>
)
// const successMessage = () => {
// }
const addMovieForm = () => (
<form >
<span>Post photo</span>
<div className="form-group">
<label className="btn btn-block btn-success">
<input
onChange={handleChange("photo")}
type="file"
name="photo"
accept="image"
placeholder="choose a file"
/>
</label>
</div>
<div className="form-group">
<input
onChange={handleChange("movie_name")}
name="photo"
className="form-control"
placeholder="movie_name"
value={movie_name}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("actor")}
name="photo"
className="form-control"
placeholder="actor"
value={actor}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("duration")}
type="number"
className="form-control"
placeholder="duration"
value={duration}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("country_of_origin")}
type="text"
className="form-control"
placeholder="country_of_origin"
value={country_of_origin}
/>
</div>
<div className="form-group">
<input
onChange={handleChange("director")}
type="text"
className="form-control"
placeholder="director"
value={director}
/>
</div>
<button type="submit" onClick={onSubmit} className="btn btn-success mb-2">
Add Movie
</button>
</form>
);
return (
<div>
<Navbar/>
<div className='container'style={{height:'0px'}}>
<Link to='/admin/dashboard'> <h1 className=' bg-info text-white p-4 text-decoration-none'>Admin Home</h1> </Link>
<div className='row bg-dark text-white rounded'>
<div className='col-md-8 offset-md-2'>
{successMessage()}
{addMovieForm()}
</div>
</div>
</div>
<Footer/>
</div>
)
}
export default AddMovie;
adminapicall.js
this is code where my frontend talk with backend
import {API} from '../backend';
//products calls
//add movie
export const addMovie = (userId,token,movie)=>{
return fetch(`${API}/movie/addMovie/${userId}`,{
method : "POST",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
},
body:movie
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
//get all movie
export const getAllMovies = () => {
return fetch(`${API}/movies`,{
method : "GET"
})
.then(response => {
return response.json();
})
.catch(err => console.log(err))
}
//get a movie
export const getMovie = movieId =>{
return fetch(`${API}/movie/${movieId}`,{
method : "GET"
})
.then(response => {
return response.json();
})
.catch(err => console.log(err))
}
//update movie
export const updateMovie = (movieId,userId,token,movie)=>{
return fetch(`${API}/movie/${movieId}/${userId}`,{
method : "PUT",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
},
body:movie
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
//delete movie
export const deleteMovie = (movieId,userId,token)=>{
return fetch(`${API}/movie/${movieId}/${userId}`,{
method : "DELETE",
headers:{
Accept:'Application/json',
Authorization: `Bearer ${token}`
}
}).then(response => {
return response.json()
})
.catch(err => console.log(err))
}
i think ur mistaken here,
const [values,setValues] = useState({
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
error:'',
addedMovie:'',
getRedirect:false,
formData:'' // <-
})
const {movie_name,actor,country_of_origin,duration,director,photo,loading,error,addedMovie,getRedirect,formData} = values;
const handleChange = name => event => {
const value = name === "photo" ? event.target.files[0] : event.target.value
formData.set(name,value); // <-
setValues({...values,[name]:value})
};
const onSubmit = (e) => {
e.preventDefault();
setValues({...values,error:'',loading:true})
addMovie(user._id,token,formData).then(data =>{
// ^^^^^^^^ <-
if(data.error){
setValues({...values,error:data.error})
}else{
setValues({
...values,
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
addedMovie: data.movie_name
})
}
})
You might wanted to do somethig like this,
const [values,setValues] = useState({
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
error:'',
addedMovie:'',
getRedirect:false,
})
const {movie_name,actor,country_of_origin,duration,director,photo,loading,error,addedMovie,getRedirect} = values;
const handleChange = name => event => {
const value = name === "photo" ? event.target.files[0] : event.target.value
setValues({...values,[name]:value})
};
const onSubmit = (e) => {
e.preventDefault();
setValues({...values,error:'',loading:true})
addMovie(user._id,token,JSON.stringify(values)).then(data =>{
if(data.error){
setValues({...values,error:data.error})
}else{
setValues({
...values,
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
addedMovie: data.movie_name
})
}
})
const [values,setValues] = useState({
movie_name:'',
actor:'',
country_of_origin:'',
duration:'',
director:'',
photo:'',
loading:false,
error:'',
addedMovie:'',
getRedirect:false,
formData:new FormData() <---- declare form, data like this
})
I know it's late but according to my study,
we need to check if we are on a server-side environment or client environment (browser).
we can check(for client-side), (process.browser == true) but since now it is deprecated we can use
**(typeof window !== 'undefined')**
const [values, setValues] = useState({
formData: typeof window !== 'undefined' && new FormData(),
// other values
});
Refer to https://github.com/zeit/next.js/issues/5354#issuecomment-520305040
Also,
If you're using Next.js newer versions, you can use getStaticProps or getServerSideProps instead of getInitialProps.

Resources