doesn't render react component when I navigate from another page - javascript

import React , {useContext, useEffect, useState} from 'react'
import { Button } from "#mui/material";
import Grid from '#mui/material/Grid';
import { styled } from '#mui/material/styles';
import Box from '#mui/material/Box';
import Paper from '#mui/material/Paper';
import AddIcon from '#mui/icons-material/Add';
import RemoveIcon from '#mui/icons-material/Remove';
import IconButton from '#material-ui/core/IconButton';
import axios from 'axios'
//import {ids} from "./Scanner"
let tot = 0;
let newproduct=[]
let ids=[{productid:'9501101530003'}]
const Item = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
...theme.typography.body2,
padding: theme.spacing(1),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
const Item2 = styled(Paper)(({ theme }) => ({
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
...theme.typography.body2,
padding: theme.spacing(2.5),
textAlign: 'center',
color: theme.palette.text.secondary,
}));
function Product (props){
console.log("g")
console.log(props)
return( <Box sx={{ width: '100%' }}>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={6}>
<Item2>{props.product.productName}</Item2>
</Grid>
<Grid item xs={6}>
<Item2>{props.product.price}</Item2>
</Grid>
{/* <Grid item xs={4} >
<Item>
<IconButton onClick={()=>{qty++}} color="primary">
<AddIcon fontSize='small'/>
</IconButton>
{qty}
<IconButton color="primary">
<RemoveIcon fontSize='small'/>
</IconButton>
</Item>
</Grid> */}
</Grid>
</Box>
)
}
export default function Cart (){
console.log(ids)
const [product,setproduct] = useState([])
useEffect(()=>{
ids.forEach(element => {
console.log(element)
axios.post('http://localhost:4000/app/barcode',element)
.then((response)=>{
console.log(response)
newproduct= product
newproduct.push(response.data.product)
setproduct(newproduct)
console.log(product)
product.forEach((prod)=>tot=tot+parseInt(prod.price))
console.log(tot)
})
});
})
return(
<div >
<Box sx={{ width: '100%' }}>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
<Grid item xs={6}>
<Item>product name</Item>
</Grid>
<Grid item xs={6}>
<Item>price</Item>
</Grid>
{/* <Grid item xs={4}>
<Item>
quantity
</Item>
</Grid> */}
</Grid>
</Box>
{product.map((element,index)=>(<Product key={index} product={element} />))}
<Box sx={{ width: '100%' }}>
<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }} justifyContent="center"
alignItems="center" >
<Grid item xs={4}>
<Item>{tot}</Item>
</Grid>
</Grid>
</Box>
<div>
<Button href='/payment'>pay</Button>
</div>
</div>
)
}
I want to display the product name and price which I have stored in a database . when the program runs it dosen't show product name nor price but when I re run the program it shows the product name and price.I have populated the product hook with a request from the database and pushing the details of all the products to an array of objects called products.when the program is first run it consolelogs the details of the products correctly.but it doesnt render the product name and price.the same thin
this is the backend code.
const express = require('express')
const router = express.Router()
const signUpTemplateCopy = require('../server/models/signupmodel')
const ownersignUpcopy = require('../server/models/ownersignupmodel')
const barcode = require('./models/barcode')
router.post('/signup',async (request,response) => {
const signedUpUser = new signUpTemplateCopy({
firstName : request.body.firstName,
lastName: request.body.lastName,
email: request.body.email,
password: request.body.password,
})
//signedUpUser.save()
const user = await signUpTemplateCopy.findOne({email:request.body.email})
if(!user){
signedUpUser.save()
return response.json({status:"ok"})
}
else{
return response.json({status:"error",error:"user already exist"})
}
})
router.post('/signin',async(request,response)=>{
const user = await signUpTemplateCopy.findOne({email:request.body.email,password:request.body.password})
console.log(user)
if(user){
return response.json({status:"ok"})
}
else{
return response.json({status:"error",error:"invalid login"})
}
})
router.post('/ownersignup',async(request,response) => {
const signedUpUser = new ownersignUpcopy({
firstName : request.body.firstName,
lastName: request.body.lastName,
email: request.body.email,
password: request.body.password,
})
//signedUpUser.save()
const user = await ownersignUpcopy.findOne({email:request.body.email})
if(!user){
signedUpUser.save()
return response.json({status:"ok"})
}
else{
return response.json({status:"error",error:"user already exist"})
}
})
router.post('/ownersignin',async(request,response)=>{
const user = await ownersignUpcopy.findOne({email:request.body.email,password:request.body.password})
console.log(user)
if(user){
return response.json({status:"ok"})
}
else{
return response.json({status:"error",error:"invalid login"})
}}
)
router.post('/barcode',async(request,response)=>{
const product = await barcode.findOne({productid:request.body.productid})
response.json({product})
})
module.exports = router

Related

How to pass data from input field to parent component using context API in React?

I have an input field in child component. If you type in valid wallet address it should display wallet balance in parent component.
I don't know how to pass that e.target.value we are reading from input field.
I tried to do this function in parent component - Dashboard.
const [walletBalance, setWalletBalance] = useState('');
const getWalletBalance = async () => {
try {
const web3 = new Web3(Web3.givenProvider || 'ws://localhost:3000');
for (const wallet of dummyWallets) {
const balance = await web3.eth.getBalance(wallet.address);
console.log(balance);
const balanceConvertedFromWeiToEth = await Web3.utils.fromWei(balance, 'ether');
const shortenedBalance =
balanceConvertedFromWeiToEth.length >= 10
? balanceConvertedFromWeiToEth.slice(0, 10)
: balanceConvertedFromWeiToEth;
setWalletBalance(shortenedBalance);
}
} catch (error) {
console.error(error);
throw new Error('No wallet found');
}
};
render (
<p>Wallet balance: {walletBalance}</p>
and then pass this function down to child component with input field (need to prop drill 3 times for that) and in child component say:
const [inputText, setInputText] = useState('');
const handleInputChange = (e) => {
setInputText(e.target.value);
if (inputText === wallet.address) {
getWalletBalance()
}
};
render (
<input value={inputText} onChange={handleInputChange} />
)
It didn't work. No errors. Just nothing happens.
Then I thought that I need to do the other way around: Instead of trying to pass getWalletBalance() down as props, I need to read data from input field and pass that data to parent component, because parent needs to have access to the input field and read from it to be able to display wallet balance in parent.
I've also tried to create context:
import React, { useState, createContext } from 'react';
import { dummyWallets } from '../mocks/dummyWallets';
import Web3 from 'web3';
export const WalletContext = createContext();
// eslint-disable-next-line react/prop-types
export const TransactionProvider = ({ children }) => {
const [inputText, setInputText] = useState('');
const [walletBalance, setWalletBalance] = useState('');
const handleInputChange = async (e) => {
setInputText(e.target.value);
const web3 = new Web3(Web3.givenProvider || 'ws://localhost:3000');
for (const wallet of dummyWallets) {
if (inputText === wallet.address) {
const balance = await web3.eth.getBalance(wallet.address);
console.log(balance);
const balanceConvertedFromWeiToEth = await Web3.utils.fromWei(balance, 'ether');
const shortenedBalance =
balanceConvertedFromWeiToEth.length >= 10
? balanceConvertedFromWeiToEth.slice(0, 10)
: balanceConvertedFromWeiToEth;
setWalletBalance(shortenedBalance);
}
}
};
return (
<WalletContext.Provider
value={{ walletBalance, handleInputChange, inputText, setInputText,
setWalletBalance }}>
{children}
</WalletContext.Provider>
);
};
Then pass handleInputChange to onChange in child component and inputText as value, then use walletBalance in parent component.
All context things walletBalance, handleInputChange, inputText, setInputText and setWalletBalance threw undefined error.
Here is child component consuming data from context:
import React, { FC, useState, useContext } from 'react';
import { Formik, Form, Field } from 'formik';
import { Button, InputAdornment, Box, Grid } from '#material-ui/core';
import TextField from '#eyblockchain/ey-ui/core/TextField';
import { Search } from '#material-ui/icons';
import SvgEthereum from '../../../images/icon/Ethereum';
import { makeStyles } from '#material-ui/styles';
import { Theme } from '#material-ui/core';
import { dummyWallets } from '../../../shared/mocks/dummyWallets';
import Web3 from 'web3';
import { WalletContext } from '../../../shared/context/WalletContext';
const etherIconBorderColor = '#eaeaf2';
const useStyles = makeStyles((theme: Theme) => ({
etherIconGridStyle: {
padding: '16px 0 0 0'
},
etherIconStyle: {
fontSize: '220%',
textAlign: 'center',
color: theme.palette.primary.light,
borderTop: `solid 1px ${etherIconBorderColor}`,
borderBottom: `solid 1px ${etherIconBorderColor}`,
borderLeft: `solid 1px ${etherIconBorderColor}`,
padding: '5px 0 0 0',
[theme.breakpoints.down('sm')]: {
fontSize: '150%',
lineHeight: '43px'
}
},
buttonStyle: {
paddingTop: theme.spacing(2)
},
searchIconStyle: {
color: theme.palette.primary.light
}
}));
const onSubmitHandler = () => {
return;
};
const SearchInputForm: FC<any> = (props) => {
const { walletBalance, handleInputChange, inputText } = useContext(WalletContext);
const classes = useStyles();
return (
<Formik
onSubmit={onSubmitHandler}
initialValues={{ name: '' }}
render={({ values }) => {
return (
<Form>
<Grid container>
<Grid item xs={1} className={classes.etherIconGridStyle}>
<Box className={classes.etherIconStyle}>
<SvgEthereum />
</Box>
</Grid>
<Grid item xs={11}>
<Field
required
name="name"
placeholder={props.placeholdervalue}
value={inputText}
component={TextField}
onChange={handleInputChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Search fontSize="large" className={classes.searchIconStyle} />
</InputAdornment>
)
}}
/>
</Grid>
<Grid item xs={12}>
<Box
display="flex"
justifyContent="flex-end"
alignItems="flex-end"
className={classes.buttonStyle}>
<Button type="submit" variant="contained" color="secondary" size="large" disabled>
Create Alert
</Button>
</Box>
</Grid>
</Grid>
</Form>
);
}}
/>
);
};
export default SearchInputForm;
Here is parent component where I pull walletBalance from context:
const Dashboard: FC<any> = () => {
const { walletBalance } = useContext(WalletContext);
const classes = useStyles();
return (
<>
<Container maxWidth={false} className={classes.dashboardContainer}>
<Grid>
<Box data-testid="alert-page-heading">
<Typography variant="h3">Alerts</Typography>
</Box>
<Box data-testid="alert-page-subheading">
<Typography className={classes.subHeadingStyle}>
Monitor the Web 3.0 for interesting blockchain events
</Typography>
</Box>
</Grid>
<Grid container spacing={4}>
<Grid item xs={12} sm={8}>
<Box className={classes.dashboardCard}>
<Box className={classes.searchBox}>
<SearchTabs />
</Box>
<Box
sx={{
display: 'flex',
justifyContent: 'space-between'
}}>
<Box
sx={{
height: '60%',
padding: '1%',
fontSize: 20
}}>
<a href="http://localhost:3000/" className={classes.backToAlertsLink}>
Back to my alerts
</a>
<p className={classes.boldText}>Recent transactions</p>
</Box>
<Box sx={{ height: '60%', padding: '4%', fontSize: 20 }}>
<span>Wallet Balance</span>
<span className={classes.balanceNumber}>{walletBalance} ETH</span>
</Box>
</Box>
</Box>
</Grid>
<Grid item xs={12} sm={4}>
<Box className={classes.dashboardCard}>
<Box sx={{ height: '60%', padding: '2%', fontSize: 20, fontWeight: 'bold' }}>
Top 10 alerts
</Box>
</Box>
</Grid>
</Grid>
</Container>
</>
);
};
export default Dashboard;
The problem is that I pull handleChange from context and apply to input field in child component to read the value from the input and then pull walletBalance from context in parent but that walletBalance is not updated (doesn't contain input value in it).
Can someone please share knowledge on how to read data from child component input field and display something from that in parent component?
Any advice is appreciated. Thank you.

Issue with javascript map function

I am working with the map function in react and I am getting all my info to map except for my button ref. Below is the code. The data is getting pulled from a database and passed as a prop as well. When I filter the list I get the look I am looking for but when I go to select a doctor I only get the last name for the doctor that was the last item iterated, and this is across all the buttons when I click them. Where am I going wrong if I may ask.
import {
Button,
Card,
CardActions,
CardContent,
Grid,
Typography,
} from "#material-ui/core";
import { makeStyles } from "#material-ui/styles";
import { useRef } from "react";
const styles = makeStyles({
bound: {
margin: "40px 200px",
position: "relative",
},
card: {
maxWidth: "70%",
margin: "50px auto",
borderStyle: "solid",
borderRadius: "50px",
borderColor: "black",
borderWidth: "3px",
"&:hover": {
boxShadow: "black",
borderColor: "green",
},
},
null: {
display: "none",
},
btn: {
margin: "20px 0 0 0",
borderRadius: "20px",
"&:hover": {
backgroundColor: "green",
color: "white",
},
},
});
const SearchResult = (props) => {
const doctorList = props.doctor;
const selectedRef = useRef();
const selectedHandler = (e) => {
console.log(e.target.target);
console.log(selectedRef.current.value);
};
const doctorCard = (doctorList) => {
return (
<Card
variant="outlined"
className={`${doctorList ? classes.card : classes.null}`}
key={doctorList.user_id}
id={doctorList.user_id}
>
<CardContent>
<Grid container>
<Grid xs={6} md={6} lg={6} item>
<img src="#" alt="Img.png" />
</Grid>
<Grid xs={6} md={6} lg={6} item>
<Typography variant="h6">
Dr. {doctorList.first_name} {doctorList.last_name}
</Typography>
<Typography variant="h6">
Speciality: {doctorList.title}
</Typography>
<Typography variant="h6">
Primary Language: {doctorList.primary_language}
</Typography>
</Grid>
</Grid>
<CardActions>
<Button
variant="contained"
className={classes.btn}
type="submit"
ref={selectedRef}
value={doctorList.last_name}
onClick={selectedHandler}
size="large"
fullWidth
>
Select
</Button>
</CardActions>
</CardContent>
</Card>
);
};
const classes = styles();
return (
<div className={classes.bound}>{doctorList.doctor.map(doctorCard)}</div>
);
};
export default SearchResult;
OUTPUT
You are looping list and using common reference 'selectedRef' in you list component. Once list rendering finishes, last_name of last item in your array is being stored in 'selectedRef' reference. That's why whenever you click it's always getting last item.
To resolve this you might want to break component on granular level. Use two component ItemList and ListItem. ItemList will simply loop array and in ListItem component create reference to each item while looping. That should resolve your issue.
const ItemList = (props) => {
const renderList=(doctor)=>{
return <ListItem key={`doctor-${doctor.id}`} {...doctor}/>
}
return <div>{props.data.map(renderList)}</div>
}
const ListItem = () => {
// reference below create new reference for every item
const selectedRef = useRef();
// rest of logic to render doctor card
}

How to map data to react component?

I have data returned from the backend now i am trying to map it to react component which is throwing an error Cannot read property of null what is correct way to print keys in the div or card , i have also attached the data
index.js
import React, { Component } from 'react';
import './app.css';
import ReactImage from './react.png';
import AppBar from '#mui/material/AppBar';
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Typography from '#mui/material/Typography';
import IconButton from '#mui/material/IconButton';
import MenuIcon from '#mui/icons-material/Menu';
import Paper from '#mui/material/Paper';
import Grid from '#mui/material/Grid';
import { styled } from '#mui/material/styles';
export default class JOB_DESC extends Component {
state = { data: null };
async componentDidMount() {
try {
const response = await fetch('/api/getUsername');
const data = await response.json();
this.setState({ data: data });
} catch (e) {
if (e.name != "AbortError") this.setState({ error: e.message });
}
}
render() {
const data = this.state.data;
console.log("DATA", data);
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }} >
<MenuIcon />
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Job.com
</Typography>
</Toolbar>
</AppBar>
<div style={{ padding: 20 }}>
<Grid container spacing={4}>
<Grid item xs={12}>
<p>`{data["User Account"]}`</p>
<p>`{data["User Location"]}`</p>
<p> `{data["Company Name"]}`</p>
</Grid>
</Grid>
</div>
</Box>
);
}
}
data
{ ‘User Account': Admin’,
‘User Location': ': New York, NY',
'Company Name': ': Millennium’ }
It looks like by the time your component gets rendered, data will still be null as you've set it to null. So attempting to index null will give you Cannot read property of null.
What you'd want to do is wrap your component with a condition to check if data exists by the time it renders.
{ data && (
<div style={{ padding: 20 }}>
<Grid container spacing={4}>
<Grid item xs={12}>
<p>`{data["User Account"]}`</p>
<p>`{data["User Location"]}`</p>
<p> `{data["Company Name"]}`</p>
</Grid>
</Grid>
</div>
)}

how can i append selected row data in another table

what my task is I am using a table with two different conditions like in the first table whatever data coming I will show that in the first table and in the second table whatever row I select in the first table that I want to show in the second table as the second table I called select summary so my task is in the first table whatever row I selected in need to how that row in the second table I am using same table component for this for better you can see CodeSandBox link
import React, { useState, useMemo, useEffect } from "react";
import {
Grid,
makeStyles,
CardContent,
Card,
Box
} from "#material-ui/core";
import EnhancedTable from "./EnhancedTable";
const useStyles = makeStyles((theme) => ({
root: {
padding: theme.spacing(0, 2, 2),
},
formGrid: {
padding: theme.spacing(2),
},
cardColor: {
borderColor: "#0bb7a7",
},
}));
function AddToExclusionList() {
const classes = useStyles();
const [sanctionsList, setSanctionsList] = useState([]);
const updateListsRow = ({ index, value, row }, listType) => {
switch (listType) {
case "sanctions":
setSanctionsList((prevState) => {
prevState[index].status = value;
return [...prevState];
});
break;
default:
}
};
return (
<Grid className={classes.root}>
<Grid item xs={12} style={{ textTransform: "capitalize" }}>
<Card className={classes.cardColor} variant="outlined">
<CardContent>
<>
<EnhancedTable
show={true}
step="first"
/>
</>
</CardContent>
</Card>
</Grid>
<Box mt={3}></Box>
<Grid item xs={12} style={{ textTransform: "capitalize" }}>
<Card className={classes.cardColor} variant="outlined">
<CardContent>
<>
<h3>summary table</h3>
<EnhancedTable
checkboxToggle={(rowDetails) => {
updateListsRow(rowDetails, "sanctions");
}}
/>
</>
</CardContent>
</Card>
</Grid>
</Grid>
);
}
export default AddToExclusionList;
CodeSandBox Link
You've achieved your goal very weird! Anyway, based on your code in codesandbox. You need to add a state to AddToExclusionList component, like this:
const [newRows, setNewRows] = useState([]);
const setSummaryRows = (selectedRows) => {
const copy = [...rows];
const filteredRows = copy.filter((x) => selectedRows.includes(x.name));
setNewRows(filteredRows);
};
We need the mentioned state to update the summary table's rows.
Also add rows and setNewRows prop to EnhancedTable and give it rows from out of the component. In addition move rows and createData to App.js. So you should use EnhancedTable in App.js same as bellow:
<Grid className={classes.root}>
<Grid item xs={12} style={{ textTransform: "capitalize" }}>
<Card className={classes.cardColor} variant="outlined">
<CardContent>
<>
<h3>first table</h3>
<EnhancedTable
// passing data for rendering table according condition
step="first"
rows={rows}
setNewRows={(selected) => {
setSummaryRows(selected);
}}
/>
</>
</CardContent>
</Card>
</Grid>
<Box mt={3}></Box>
<Grid item xs={12} style={{ textTransform: "capitalize" }}>
<Card className={classes.cardColor} variant="outlined">
<CardContent>
<>
<h3>summary table</h3>
<EnhancedTable
// trying to pasing selected data
rows={newRows}
setNewRows={() => {}}
/>
</>
</CardContent>
</Card>
</Grid>
</Grid>
And the last part is using useEffect based on selected in EnhancedTable component:
useEffect(() => {
setNewRows(selected);
}, [selected]);

Encountered comments is undefined error in react

I'm trying to learn react I keep encountering this error while rendering the post dialog box in the website.
comments.js file:
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import withStyles from '#material-ui/core/styles/withStyles';
import { Link } from 'react-router-dom';
import dayjs from 'dayjs';
// MUI
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
const styles = (theme) => ({
...theme,
commentImage: {
maxWidth: '100%',
height: 100,
objectFit: 'cover',
borderRadius: '50%'
},
commentData: {
marginLeft: 20
}
});
class Comments extends Component {
render() {
const { comments, classes } = this.props;
return (
//Here is the error
<Grid container>
{comments.map((comment, index) => {
const { body, createdAt, userImage, userHandle } = comment;
return (
<Fragment key={createdAt}>
<Grid item sm={12}>
<Grid container>
<Grid item sm={2}>
<img
src={userImage}
alt="comment"
className={classes.commentImage}
/>
</Grid>
<Grid item sm={9}>
<div className={classes.commentData}>
<Typography
variant="h5"
component={Link}
to={`/users/${userHandle}'}
color="primary"
>
{userHandle}
</Typography>
<Typography variant="body2" color="textSecondary">
{dayjs(createdAt).format('h:mm a, MMMM DD YYYY')}
</Typography>
<hr className={classes.invisibleSeparator} />
<Typography variabnt="body1">{body}</Typography>
</div>
</Grid>
</Grid>
</Grid>
{index !== comments.length - 1 && (
<hr className={classes.visibleSeparator} />
)}
</Fragment>
);
})}
</Grid>
);
}
}
Comments.propTypes = {
comments: PropTypes.array.isRequired
};
export default withStyles(styles)(Comments);

Categories

Resources