How to clean up subscriptions in react components? (Hooks) - reactjs

Consider this code below:
import React , { useState, useEffect } from 'react'
import { Row , Col } from 'react-bootstrap'
import Product from '../components/Product'
import axios from 'axios'
const HomeScreen = () =>{
const [products , setProducts] = useState([])
useEffect(()=>{
const fetchProducts = async () =>{
const {data} = await axios.get('http://localhost:5000/api/products')
setProducts(data)
}
fetchProducts()
},[products])
return(
<>
<h2 className='my-3'>Latest Products</h2>
<Row>
{
products.map((product)=>(
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} rating = {product.rating} reviews={product.numReviews}/>
</Col>
))
}
</Row>
</>
)
}
export default HomeScreen
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React , {useState , useEffect} from 'react'
import { Row, Col, Image, ListGroup, Card, Button } from 'react-bootstrap'
import {Link} from 'react-router-dom'
import Rating from '../components/Rating'
import axios from 'axios'
const ProductScreen = ({match}) => {
const [product , setProduct] = useState({})
useEffect(()=>{
const fetchProduct = async ()=>{
const {data} = await axios.get(`http://localhost:5000/api/products/${match.params.id}`)
setProduct(data)
}
fetchProduct()
},[match])
return (
<>
<Link className='btn btn-light my-3' to='/'>
Go Back
</Link>
<Row>
<Col md={6}>
<Image src={product.image} alt={product.name} />
</Col>
<Col md={3}>
<ListGroup variant='flush'>
<ListGroup.Item>
<h3>{product.name}</h3>
</ListGroup.Item>
<ListGroup.Item>
<Rating rating={product.rating} reviews={product.numReviews}/>
</ListGroup.Item>
<ListGroup.Item>
<strong> Price: ${product.price}</strong>
</ListGroup.Item>
<ListGroup.Item>
<strong>Description :</strong> {product.description}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={3}>
<Card>
<ListGroup>
<ListGroup.Item>
<Row>
<Col>
Price :
</Col>
<Col>
<strong>${product.price}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>
Status :
</Col>
<Col>
<strong>{product.countInStock > 0 ? 'In Stock' : "Out Of Stock"}</strong>
</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item className='d-grid gap-2'>
<Button type='button' disabled={product.countInStock === 0}>
Add To Cart
</Button>
</ListGroup.Item>
</ListGroup>
</Card>
</Col>
</Row>
</>
)
}
export default ProductScreen
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
The issue is that I see "products" renders twice.
the error message is
"Can't perform a React state update on an unmounted component. This is
a no-op, but it indicates a memory leak in your application. To fix,
cancel all subscriptions and asynchronous tasks in a useEffect cleanup
function."
How can I fix that?

It's a memory leak issue. The memory leak will happen if the API server or host took some time to respond and the component was unmounted before the response was received. To avoid this issue , you can keep a boolean flag , like componentMounted = false . So the code portion will look like below
useEffect(() => {
let componentMounted = true;
const response = async () => {
// API calling
if(componentMounted) {
setData(response?.data); // null checking
}
};
fetchData();
return () => { // using return avoids the memory leak issue
componentMounted = false;
}
}, []);
The boolean flag cleans the previous effect when new effect will be executed. There are other methods to do this like using AbortController to abort the request or useStateSafe hook etc.

Related

Encountered two children with the same key...ecommerce website

why is it that there are two children with the same key
Im using React and Im trying to make ecommerce website
I dont understand the error of double keys
import React, {useEffect} from 'react'
import { Link, useParams, useNavigate, useLocation, useSearchParams } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col, ListGroup, Image, Form, Button, Card} from 'react-bootstrap'
import Message from '../components/Message'
import { addToCart } from '../actions/cartActions'
export default function CartScreen() {
const { id} = useParams()
const { search } = useLocation();
const [searchParams] = useSearchParams();
const dispatch = useDispatch();
const productID = id;
const qty = search ? Number(search.split("=")[1]) : 1;
const cart = useSelector(state => state.cart)
const { cartItems} = cart
console.log('cartItems:', cartItems)
useEffect(() => {
if(productID) {
dispatch(addToCart(productID, qty))
}
}, [dispatch, productID, qty])
return (
<Row>
<Col md={8}>
<h1>Shopping Cart</h1>
{cartItems.length === 0 ? (
<Message variant='info'>
Your cart is empty <Link to='/'>Go Back</Link>
</Message>
) : (
<ListGroup varient='flush'>
{cartItems.map(item => (
<ListGroup.Item key= { item.product }>
<Row>
<Col md={2}>
<Image src={item.image} alt={item.name} fluid rounded/>
</Col>
<Col md={3}>
<Link to={`/product/${item.product}`}>{item.name}</Link>
</Col>
<Col md={2}>
${item.price}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</Col>
<Col md={4}>
</Col>
</Row>
)
}
Im trying to load up the cart images in the CartScreen
and its telling me that there are two children with same key
In React while using the following
<ListGroup.Item key= { uniqueID }>
Every key value has to be unique such that it can identify each item in the list uniquely.
More help from this thread.
key is not unique for the elements rendered, React found two elements with same key. Could you please try modifying the map JSX inside map.
<ListGroup varient='flush'>
{cartItems.map((item, index) => (
<ListGroup.Item key= { `${item.product}i${index}` }>
<Row>
<Col md={2}>
<Image src={item.image} alt={item.name} fluid rounded/>
</Col>
<Col md={3}>
<Link to={`/product/${item.product}`}>{item.name}</Link>
</Col>
<Col md={2}>
${item.price}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>

A state mutation was detected between dispatches

I've got this issue which I do not understand. I am getting an invariant error that says a state mutation has occurred, but at a very awkward place.
Basically I've got this page:
import React, { useState, useEffect } from "react";
import {
Link,
useLocation,
useNavigate,
useSearchParams,
} from "react-router-dom";
import { Form, Button, Row, Col, Table } from "react-bootstrap";
import { LinkContainer } from "react-router-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import Loader from "../components/Loader";
import Message from "../components/Message";
import FormContainer from "../components/FormContainer";
import { register } from "../actions/userActions";
import { getUserDetails, updateUserProfile } from "../actions/userActions";
import { USER_UPDATE_PROFILE_RESET } from "../constants/userConstants";
import { listMyOrders } from "../actions/orderActions";
function ProfileScreen() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [message, setMessage] = useState("");
const dispatch = useDispatch();
const location = useLocation();
const userDetails = useSelector((state) => state.userDetails);
const navigate = useNavigate();
const { error, loading, user } = userDetails;
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
const userUpdateProfile = useSelector((state) => state.userUpdateProfile);
const { success } = userUpdateProfile;
const orderListMy = useSelector((state) => state.orderListMy);
const { loading: loadingOrders, error: errorOrders, orders } = orderListMy;
useEffect(() => {
if (!userInfo) {
navigate("/login");
} else {
if (!user || !user.name || success) {
dispatch({ type: USER_UPDATE_PROFILE_RESET });
dispatch(getUserDetails("profile"));
dispatch(listMyOrders());
} else {
setName(user.name);
setEmail(user.email);
}
}
}, [dispatch, location, userInfo, user, success]);
const submitHandler = (e) => {
e.preventDefault();
if (password != confirmPassword) {
setMessage("Passwords do not match!");
} else {
dispatch(
updateUserProfile({
id: user._id,
name: name,
email: email,
password: password,
})
);
}
};
return (
<Row>
<Col md={3}>
<h2>User Profile</h2>
{message && <Message variant="danger">{message}</Message>}
{error && <Message variant="danger">{error}</Message>}
{loading && <Loader></Loader>}
<Form onSubmit={submitHandler}>
<Form.Group controlId="name">
<Form.Label>Name</Form.Label>
<Form.Control
required
type="name"
placeholder="Enter Name"
value={name}
onChange={(e) => setName(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="email">
<Form.Label>Email Address</Form.Label>
<Form.Control
required
type="email"
placeholder="Enter Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="password">
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
placeholder="Enter Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Form.Group controlId="passwordConfirm">
<Form.Label>Confirm Password</Form.Label>
<Form.Control
type="password"
placeholder="Confirm Password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
></Form.Control>
</Form.Group>
<Button type="submit" variant="primary">
Update
</Button>
</Form>
</Col>
<Col md={9}>
<h2>My Orders</h2>
{loadingOrders ? (
<Loader />
) : errorOrders ? (
<Message variant="danger">{errorOrders}</Message>
) : (
<Table striped responsive className="table-sm">
<thead>
<tr>
<th>ID</th>
<th>Date</th>
<th>Total</th>
<th>Paid</th>
<th>Delivered</th>
<th></th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order._id}>
<td>{order._id}</td>
<td>{order.createdAt.substring(0, 10)}</td>
<td>${order.totalPrice}</td>
<td>
{order.isPaid ? (
order.paidAt.substring(0, 10)
) : (
<i className="fas fa-times" style={{ color: "red" }}></i>
)}
</td>
<td>
<LinkContainer to={`/order/${order._id}`}>
<Button className="btn-sm">Details</Button>
</LinkContainer>
</td>
</tr>
))}
</tbody>
</Table>
)}
</Col>
</Row>
);
}
export default ProfileScreen;
and in this page whenever you click on the Details button on some of the orders you get redirected to this page:
import React, { useState, useEffect } from "react";
import { Button, Row, Col, ListGroup, Image, Card } from "react-bootstrap";
import { Link, useNavigate, useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { PayPalButton } from "react-paypal-button-v2";
import Message from "../components/Message";
import Loader from "../components/Loader";
import CheckoutSteps from "../components/CheckoutSteps";
import {
createOrder,
getOrderDetails,
payOrder,
} from "../actions/orderActions";
import {
ORDER_CREATE_RESET,
ORDER_PAY_RESET,
} from "../constants/orderConstants";
function OrderScreen() {
const orderDetails = useSelector((state) => state.orderDetails);
const { order, error, loading } = orderDetails;
const orderPay = useSelector((state) => state.orderPay);
const { loading: loadingPay, success: successPay } = orderPay;
const dispatch = useDispatch();
const history = useNavigate();
const orderId = useParams();
const takenId = orderId.id;
const [sdkReady, setSdkReady] = useState(false);
const cart = useSelector((state) => state.cart);
let copyCart = Object.assign({}, cart);
if (!loading && !error) {
order.itemsPrice = order.orderItems
.reduce((acc, item) => acc + item.price * item.qty, 0)
.toFixed(2);
}
const addPayPalScript = () => {
const script = document.createElement("script");
script.type = "text/javascript";
script.src =
"https://www.paypal.com/sdk/js?client-id=ATMiiNcpLBRgha0mQCRpS5GJRC9YrATzPxyLFvWGoVsCvoxg46E0UGielBSPptskQWiqk8mrp2eQgpnC";
script.async = true;
script.onload = () => {
setSdkReady(true);
};
document.body.appendChild(script);
};
useEffect(() => {
if (!order || successPay || order._id !== Number(takenId)) {
dispatch({ type: ORDER_PAY_RESET });
dispatch(getOrderDetails(takenId));
} else if (!order.isPaid) {
if (!window.paypal) {
addPayPalScript();
} else {
setSdkReady(true);
}
}
}, [dispatch, order, orderId, successPay]);
const successPaymentHandler = (paymentResult) => {
dispatch(payOrder(takenId, paymentResult));
};
return loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<div>
<h1>Order: {order._id}</h1>
<Row>
<Col md={8}>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Shipping</h2>
<p>
<strong>Name: </strong>
{order.user.name}
</p>
<p>
<strong>Email: </strong>
<a href={`mailto:${order.user.email}`}>{order.user.email}</a>
</p>
<p>
<strong>Shipping: </strong>
{order.shippingAddress.address}, {order.shippingAddress.city}
{" "}
{order.shippingAddress.postalCode},{" "}
{order.shippingAddress.country}
</p>
{order.isDelivered ? (
<Message variant="success">
Delivered on {order.deliveredAt}
</Message>
) : (
<Message variant="warning">Not Delivered</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Payment Method</h2>
<p>
<strong>Method: </strong>
{order.paymentMethod}
</p>
{order.isPaid ? (
<Message variant="success">Paid on {order.paidAt}</Message>
) : (
<Message variant="warning">Not Paid</Message>
)}
</ListGroup.Item>
<ListGroup.Item>
<h2>Order Items</h2>
{order.orderItems.length === 0 ? (
<Message variant="info">Your order is empty</Message>
) : (
<ListGroup variant="flush">
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col md={1}>
<Image
src={item.image}
alt={item.name}
fluid
rounded
/>
</Col>
<Col>
<Link to={`/product/${item.product}`}>
{item.name}
</Link>
</Col>
<Col md={4}>
{item.qty} X ${item.price} = $
{(item.qty * item.price).toFixed(2)}
</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
</ListGroup>
</Col>
<Col md={4}>
<Card>
<ListGroup variant="flush">
<ListGroup.Item>
<h2>Order Summary</h2>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Items:</Col>
<Col>${order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping:</Col>
<Col>${order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax:</Col>
<Col>${order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total:</Col>
<Col>${order.totalPrice}</Col>
</Row>
</ListGroup.Item>
{!order.isPaid && (
<ListGroup.Item>
{loadingPay && <Loader />}
{!sdkReady ? (
<Loader />
) : (
<PayPalButton
amount={order.totalPrice}
onSuccess={successPaymentHandler}
/>
)}
</ListGroup.Item>
)}
</ListGroup>
</Card>
</Col>
</Row>
</div>
);
}
export default OrderScreen;
Here everything works perfectly fine, but when you decide to go from this page to the Home page:
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Row, Col } from "react-bootstrap";
import Product from "../components/Product";
import Loader from "../components/Loader";
import Message from "../components/Message";
import { listProducts } from "../actions/productActions";
function HomeScreen() {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { error, loading, products } = productList;
useEffect(() => {
dispatch(listProducts());
}, [dispatch]);
return (
<div>
<h1>Latest Products</h1>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
{products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
)}
</div>
);
}
export default HomeScreen;
You get the Invariant failed error at line 13, where I'm trying to dispatch the listProducts method.
I've had a situation with this error not so long ago, managed to fix it because I used to update a state directly. I understand why I used to get that error before, but this time I am way more confused than before, because this time I am literally not touching any value anywhere along the state, I am just displaying it. I've checked the backend and I get no errors there, meaning this is strictly a React problem. I do not understand why the problem is occurring only when I am trying to go from details to the home screen.

How to hide header and footer for a specific Route

I have a OrderPrintReceiptScreen, on loading this screen I want the header and footer to not show on the screen. And after that I want to use window.print(); And this way a clean PDF Receipt can be achieved. But due to header and Footer they make it very dense and I'm not sure how to remove that on loading this OrderPrintReceiptScreen.
This is the layout of App
function App() {
return (
<Router>
<Header />
<main className="py-1">
<Container>
//.....
<Route path="/order-receipt/:id" component={OrderPrintReceiptScreen} />
//.....
</Container>
</main>
<Footer />
</Router>
);
}
export default App;
OrderPrintReceiptScreen.js
import React, { useEffect } from "react";
import { Button, Row, Col, ListGroup } from "react-bootstrap";
import { Page, Text, View, Document, StyleSheet } from "#react-pdf/renderer";
import { LinkContainer } from "react-router-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import Message from "../components/Message";
import Loader from "../components/Loader";
import {
getOrderDetails,
// payOrder,
} from "../actions/orderActions";
import {
ORDER_PAY_RESET,
ORDER_DELIVER_RESET,
} from "../constants/orderConstants";
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: "row",
backgroundColor: "#E4E4E4",
},
section: {
margin: 10,
padding: 10,
flexGrow: 1,
},
});
function OrderPrintReceiptScreen({ match, history }) {
const orderId = match.params.id;
const dispatch = useDispatch();
const orderDetails = useSelector((state) => state.orderDetails);
const { order, error, loading } = orderDetails;
const orderPay = useSelector((state) => state.orderPay);
const { loading: loadingPay, success: successPay } = orderPay;
const orderDeliver = useSelector((state) => state.orderDeliver);
const { loading: loadingDeliver, success: successDeliver } = orderDeliver;
const userLogin = useSelector((state) => state.userLogin);
const { userInfo } = userLogin;
if (!loading && !error) {
order.itemsPrice = order.orderItems
.reduce((acc, item) => acc + item.price * item.qty, 0)
.toFixed(2);
}
useEffect(() => {
if (!userInfo) {
history.push("/login");
}
if (
!order ||
successPay ||
order._id !== Number(orderId) ||
successDeliver
) {
dispatch({ type: ORDER_PAY_RESET });
dispatch({ type: ORDER_DELIVER_RESET });
dispatch(getOrderDetails(orderId));
}
}, [dispatch, order, orderId, successPay, successDeliver]);
const printReceipt = (e) => {
e.preventDefault();
window.print();
};
return loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Page size="A4" style={styles.page}>
<View style={styles.section}>
<Text>Section #1</Text>
</View>
<View style={styles.section}>
<Text>Section #2</Text>
</View>
<Row>
<Col md={10}>
<ListGroup variant="flush">
<ListGroup.Item>
<LinkContainer to={`/order-receipt/${order._id}`}>
<Button
variant="outline-success"
className="mx-4 my-4 btn-lg"
fluid
onClick={printReceipt}
>
Download Receipt
</Button>
</LinkContainer>
</ListGroup.Item>
<ListGroup.Item>Order ID : {order._id}</ListGroup.Item>
<ListGroup.Item>
Created On : {order.createdAt.substring(0, 10)},{" "}
{order.createdAt.substring(11, 19)}
</ListGroup.Item>
<ListGroup.Item>
Order Items:
{order.orderItems.length === 0 ? (
<Message variant="info">Order is empty</Message>
) : (
<ListGroup flush>
{order.orderItems.map((item, index) => (
<ListGroup.Item key={index}>
<Row>
<Col>{item.name}</Col>
</Row>
</ListGroup.Item>
))}
</ListGroup>
)}
</ListGroup.Item>
<ListGroup variant="flush">
<ListGroup.Item>Name : {order.user.name}</ListGroup.Item>
<ListGroup.Item>
Phone Number : {order.shippingAddress.phoneNumber}
</ListGroup.Item>
<ListGroup.Item>
Shipping Address : {order.shippingAddress.address},{" "}
{order.shippingAddress.city}
{" "}
{order.shippingAddress.postalCode},{" "}
{order.shippingAddress.country}
</ListGroup.Item>
{order.isPaid ? (
<Message variant="light">
Payment Status : Paid On {order.paidAt.substring(0, 10)},{" "}
{order.paidAt.substring(11, 19)}
</Message>
) : (
<Message variant="warning">Not Paid</Message>
)}
<ListGroup variant="flush">
<ListGroup.Item>Payment Summary : </ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Items Price :</Col>
<Col>PKR {order.itemsPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Shipping Price :</Col>
<Col>PKR {order.shippingPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Tax Amount :</Col>
<Col>PKR {order.taxPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total Payable :</Col>
<Col> PKR {order.totalPrice}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Total Paid :</Col>
<Col> PKR {order.totalPricePaid}</Col>
</Row>
</ListGroup.Item>
<ListGroup.Item>
<Row>
<Col>Remaining Amount:</Col>
<Col>
{" "}
PKR {Number(order.totalPrice) - order.totalPricePaid}
</Col>
</Row>
</ListGroup.Item>
</ListGroup>
{order.isDelivered ? (
<Message variant="light">
Delivery Status : Delivered on{" "}
{order.deliveredAt.substring(0, 10)},{" "}
{order.deliveredAt.substring(11, 19)}
</Message>
) : (
<Message variant="warning">Not Delivered</Message>
)}
</ListGroup>
</ListGroup>
</Col>
{/* <Col md={4}>
</Col> */}
</Row>
</Page>
);
}
export default OrderPrintReceiptScreen;
There are 2 ways to do this:
The first method is to check your matching URL before rendering:
render() {
const {match: {url}} = this.props;
if(url.startWith('/ignore-header-path') {
return null;
} else {
// your render jsx
}
}
The second method is to use #media print:
#media print {
/* Your print styles */
.header, .footer { display: none !important; }
}
You need to create a component Like a layout inside layout you can manage conditional header and footer Like this example.
Remove the Header footer from the App file.
Have a look I hope it's helpful
const OrderPrintReceiptScreen= (props) => {
return (
<Layouts
showFooter={false}
showHeader={false}
>
<Childeren {...props} />
</Layouts>
);
};
const Layouts= ({showFooter,showHeader,children}) =>{
return (
{showHeader && <Header/>}
{children}
{showFooter && <Footer/>}
)
}
........
You can use the window.location.pathname to get the current route after that do the validation on the route if the same hide the header else show the header.
{
window.location.pathname!=="/login"? <Header/> : null
}

How to handle reusable components in React?

I'm trying to make a reusable input component. When data enters I want to handle those input data in the same place where I use that reusable input component. Not passing that as props.
I'm getting an error
Uncaught TypeError: Cannot read property 'value' of undefined
Can anyone give me any idea about how to handle data in such an instance?
InputFieldWithImage.js
import React, {useState} from "react";
import { Form, FormGroup, Input } from 'reactstrap';
function InputFieldWithImage(props) {
const [inputType] = useState(props.type)
const [inputValue, setInputValue] = useState('')
function handleChange(event){
console.log("Input.js");
console.log(inputValue);
setInputValue(event.target.value);
if(props.onChange) props.onChange(inputValue)
}
return (
<>
<Input type={inputType} value={inputValue} name="input-form" onChange={handleChange} class="inputclass"/>
</>
);
}
export default InputFieldWithImage;
AddTicket.js
import { Row, Col } from 'reactstrap';
import { Form, FormGroup, Input } from 'reactstrap';
import ActionButton from './../../components/ButtonComponent';
import InputFieldWithImage from './../../components/InputField/InputFieldWithImage'
import { render } from 'react-dom';
import ReactQuill from 'react-quill';
const AddTicket = (props) => {
const [assignee, setAssignee] = useState('');
const handleSubmit = (evt) => {
evt.preventDefault();
console.log('Assignee:' + assignee);
props.handleClose();
};
const test = () => {
console.log("text");
console.log('Assignee:' + assignee);
};
return (
<div className="popup-box">
<div className="box">
{/* <span className="close-icon" onClick={props.handleClose}>
x
</span> */}
<Form onSubmit={handleSubmit} style={{paddingLeft:30,paddingTop:50}}>
<Row style={{ paddingBottom: 50 }}>
<Col sm={11} xs={11} md={11}>
<h1>Add new ticket </h1>
</Col>
<Col onClick={props.handleClose} m={1} xs={1} md={1}>
<h1 className="close-icon">X </h1>
</Col>
</Row>
<FormGroup>
<Row style={{ marginBottom: '25px' }}>
<Col sm={2}>
<h4>Assignee</h4>
</Col>
<Col sm={2}>
<InputFieldWithImage value={assignee} onChange={(e) => setAssignee(e.target.value)} />
</Col>
</Row>
</FormGroup>
<Row>
<Col sm={2}></Col>
<Col>
<ActionButton text="Send" />
</Col>
</Row>
</Form>
</div>
</div>
);
};
export default AddTicket;
You need to pass event instead of inputValue . As there is input.target.value . That's why its giving error
function handleChange(event) {
console.log("Input.js");
console.log(inputValue);
setInputValue(event.target.value);
if (props.onChange) props.onChange(event);
}
Here is demo: https://codesandbox.io/s/hidden-tree-vr834?file=/src/App.js

I can't use hooks. I cant setUser with object. What should I do?

I have a problem with my react hooks not running properly.
I can't update the user's state. The following image depicts the error messages I get when trying to fetch the data and render it:
It does not seem like my component will render.
Here is my component's source code as requested in the comments:
import React, { useEffect, useState } from "react";
import axios from "axios";
import map from "../map.png";
import { Row, Col } from "react-bootstrap";
const Profile = (props) => {
const { id } = props.match.params;
const [user, setUser] = useState(0);
useEffect(() => {
axios
.get(`http://jsonplaceholder.typicode.com/users`)
.then((response) => {
const userAuthor=response.data.filter( (postAuthor) => postAuthor.id !== +id);
setUser(userAuthor=>userAuthor)
})
.catch((error) => {
console.log(error);
});
},[]);
return (
<div className="content-card">
{
console.log(user)
}
<Row className="justify-content-center post">
<Col md="6">
<h1 className="profile-name">{user.name}</h1>
<Row>
<Col md="3" className="profile-key">
Username
</Col>
<Col md="9" className="profile-value">
{user.username}
</Col>
<Col md="3" className="profile-key">
Email
</Col>
<Col md="9" className="profile-value">
{user.email}
</Col>
<Col md="3" className="profile-key">
Phone
</Col>
<Col md="9" className="profile-value">
{user.phone}
</Col>
<Col md="3" className="profile-key">
Website
</Col>
<Col md="9" className="profile-value">
{user.website}
</Col>
<Col md="3" className="profile-key">
Company
</Col>
<Col md="9" className="profile-value">
{user.company}
</Col>
</Row>
</Col>
<Col md="6">
<img src={map} />
</Col>
</Row>
<h2>{user.name}</h2>
</div>
);
};
export default Profile;
This is a problem which occurs when trying to render objects. Your state hooks are just fine. It seems from the comments that you're trying to render user.company which is an object. By changing this to user.company.name your code should run just fine
This is an error because you trying to render an objects !
You can't to return a console.log(user) as UI components, just delete it from return then can you use it after useEffect OR render some data in your UI like name
Your state hooks are likely just fine.

Resources