history.push() not working while sending the data - javascript

I have defined a route in Main component as:
<Route path="/user/:action?/:name?" component={DataForm} />
MainDataCard component:
var data = [ {name: 'abc", label: "ABC", path:"/assets/data/source1.jpg" },
{name: 'pqr", label: "PQR", path:"/assets/data/source2.jpg" },
{name: 'xyz", label: "XYZ", path:"/assets/data/source3.jpg" },
]
I am iterating over a data array and onClick of each card, I ll be navigating to another component which is DataForm. While pushing, I need to send the selected card object.
{data.map((card, index) => {
return (
<Card
key={index}
className="cardStyle"
onClick={() => {
this.onClickForm(card);
}}
>
<CardContent className="cardContent">
<Grid container>
<Grid item md={12}>
<img src={card.path} alt="card" />
</Grid>
<Grid item md={12}>
<Typography color="textSecondary" gutterBottom>
{card.name}
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
onClickForm = card => {
const {action} = this.props; // action value can be add/update. Currently action = "add"
this.props.history.push({
pathname: `/user/${action}/${card.label}`,
state: { card: card }
});
};
In DataForm component, its showing that card is undefined. It means the data is not being sent to DataForm component. Why is it so?
Thanks in advance.

Related

How to show list items after state changes in react-redux

I have a menu bar that shows category of my shop. When I click on a category a product list of that category should be shown on my shop component (also I use redux library). It works correctly for first time, but when I click on another category the state changes and the filter products update too but they don't show on my shop component. I must click a button on page to show updated list in shop component. How can I show them immediately after updating?
App.jsx
<Menubar/>
<Routes>
<Route path='/shopping' element={<Shop />}></Route>
</Routes>
Menubar.jsx
export default function MenuBar() {
const products = useSelector(state=>state.products);
const navigate = useNavigate();
const getCategory = (e) => {
let category = e.target.innerText;
dispatch(filterProByCategory(products, category));
navigate('/shopping');
}
return (
<>
<ul>
<li onClick={(e)=>getCategory(e)}>
Fashion
</li>
</ul>
</>
)
}
Shop.jsx
export default function Shop() {
const products = useSelector(state => state.filters.filterProducts);
const [filterProducts, setFilterproducts] = useState(products);
return (
<>
<Grid item xs={12} md={8} dir='rtl'>
<Card sx={{ minWidth: 275 }}>
<CardContent>
{/* */}
<Grid container spacing={1}>
{filterProducts && filterProducts.map((product, index) => (
<Grid item xs={12} md={4}>
<ProductCard product={product} key={index} />
</Grid>
))}
</Grid>
</>
)
}
Just use the direct result of products instead of using it for creating another state variable filteredProducts with useState
export default function Shop() {
const products = useSelector(state=>state.filters.filterProducts);
// const [filterProducts , setFilterproducts] = useState (products);
return (
<>
<Grid item xs={12} md={8} dir='rtl'>
<Card sx={{ minWidth: 275 }}>
<CardContent>
{/* */}
<Grid container spacing={1}>
{products && products.map((product , index)=>(
<Grid item xs={12} md={4}>
<ProductCard product={product} key={index}/>
</Grid>
))}
</Grid>
</>
)
}

Looping through the data object and Mapping Header to values in React

I have a question on how to use this data to map the headers to it's corresponding values and put that on the UI
This is how the data is structured:
{
"data": {
"details": [
{
"address_line_1": "C O Cwtsatotravel",
"address_line_2": "Not Available",
"city_name": "Arlington",
"state_name": "-",
"country_name": "Japan",
"postal_code": "22203",
"phone_number": "7638527755",
}
]
}
}
This is what I am trying to do in react
const profile_info = data?.details;
const profileHeaders = [
'Address1',
'Address2'
'City',
'State',
'Postal Code',
'Country',
'Phone',
];
return (
<Grid
id="top-card"
className={classes.mainContainer}
container
style={{
marginBottom: '4px',
}}
>
{/* <Grid item md={11} lg={11} id="item-card"> */}
<Grid container item>
<Typography variant="subtitle1">
{profile_info.agency_name}
</Typography>
</Grid>
<Grid
container
style={{
backgroundColor: '#f9f9f9',
}}
>
{profileHeaders.map((v) => (
<Grid
item
style={{
padding: '0px 4px',
}}
>
<Typography className={classes.profileData} gutterBottom={true}>
{v}
</Typography>
<Typography className={classes.profileData}>
{' '}
{profile_info[v]}
</Typography>
</Grid>
))}
</Grid>
</Grid>
);
When I do this, it's getting me all blank values on the UI for the headers
Please help, thank you !
Encode your headers using the same [as in data] keys:
const headers = {
"address_line_1": "Address1",
"address_line_2": "Address2",
"city_name": "City",
later, you can list it
Object.entries(headers).forEach(([key, value]) => console.log(`${key}: ${value}`));
console.log(data) to see its structure and use const to 'alias' iterable (object with props or array) element:
// choose the right data source - depends on what logged out
// console.log(data);
// if(data) console.log(data.details); //... step by step
// const profile_info = data?.details;
// const profile_info = data?.data.details;
const profile_info = data?.details[0]; // object in array here
render values from both headers and profile_info
Object.entries(headers).forEach(([key, value]) => (
<Grid
key={key}
item
style={{
padding: '0px 4px',
}}
>
<Typography className={classes.profileData} gutterBottom={true}>
{value}
</Typography>
<Typography className={classes.profileData}>
{' ??? use css instead! '}
{profile_info[key]}
</Typography>
</Grid>
or you can do the same using .map (you can use index if required)
Object.keys(headers).map((key, idx) => (
<Element key={key}>
<Name title={headers[key]} />
<Value data={profile_info[key]} />
There is some crucial erros on your code:
const profile_info = data?.details;
Your details are stored on property data.data.details, not data.details
So fix this, first:
const profile_info = data?.data.details;
The items in ProfileHeaders are not mapped like properties in profile_info: you have a profile_info['address_line_1'], but not profile_info['Address1'], wich is what you are trying to do in your component.
To make this work the way you want, you should map title and property correctly.
const profileHeaders = [
{
title: "Address1",
property: "address_line_1"
},
{
title: "Address2",
property: "address_line_2"
},
// map all other properties like above.
]
then you can go for that:
{profileHeaders.map((v) => (
<Grid
item
style={{
padding: '0px 4px',
}}
>
<Typography className={classes.profileData} gutterBottom={true}>
{v.title}
</Typography>
<Typography className={classes.profileData}>
{' '}
{profile_info[v.property]}
</Typography>
</Grid>
))}
I am not checking if profile_info is undefined, but you must do it in your component to avoid errors.

Render run twice times

I've a list of countries which i would like show some info related to the country. I run a loop in order to show the info for each country. I've created a component for a country.
const CountryCard = ({ info }) => {
const { country, infoForLastDate, path } = info
return (
<Card >
<CardContent>
<Typography variant="h5" component="h2" >
{country.name}
</Typography>
<Flag oneToOne={country.oneToOne} fourToThree={country.fourToThree} />
<Typography variant="body2" >
Confirmed: {infoForLastDate.confirmed}
</Typography>
<Typography variant="body2" component="p">
Recovered: {infoForLastDate.recovered}
</Typography>
<Typography variant="body2" component="p">
Deaths: {infoForLastDate.deaths}
</Typography>
</CardContent>
<CardActions>
<Link href={path}>
See more
</Link>
</CardActions>
</Card>
)
}
export default CountryCard
Also, I've created another component to show the flag related to the country.
import React from 'react'
import { imageUrlFor } from '../lib/image-url'
const Flag = ({ oneToOne, fourToThree }) => {
const url = imageUrlFor(oneToOne.asset._id)
return (
<img src={url} />
)
}
export default Flag
I get the error TypeError: oneToOne is null
i don't know why it is like the flags render twice times. when I debugged, first time oneToOne property has a value, but at the end is run again and is null
Why is it happens?
Edit: Add CountryList component:
const CountryList = ({list}) => {
return (
<Grid container spacing={3}>
{ list.length > 1 && list.map(country => {
const countryWithPath = {
...country,
path: `/country/${country.country.name.toLowerCase().replace(' ', '-').replace('*', '')}`
}
return (
<Grid item xs={12} sm={6} key={country._id} >
<CountryCard info={countryWithPath} />
</Grid>)
})
}
</Grid>
)
}
export default CountryList

How can I set a component initial state with another state before render?

I am having a json file with data
{
data = [ {name: 'abc", label: "ABC",type: "hetero", path:"/assets/data/source1.jpg" },
{name: 'pqr", label: "PQR",type: "homo", path:"/assets/data/source2.jpg" },
{name: 'xyz", label: "XYZ",type: "hetero", path:"/assets/data/source3.jpg" },
]
}
This is the Parent class which is displaying the cards. On click of cards, It will navigate to another component which is DataForm.
class MainDataCard extends React.Component{
onClickForm = card => {
const {action} = this.props; // action value can be add/update. Currently action = "add"
this.props.history.push(`/user/${action}/${card.label}`);
};
render() {
{data.map((card, index) => {
return (
<Card
key={index}
className="cardStyle"
onClick={() => {
this.onClickForm(card);
}}
>
<CardContent className="cardContent">
<Grid container>
<Grid item md={12}>
<img src={card.path} alt="card" />
</Grid>
<Grid item md={12}>
<Typography color="textSecondary" gutterBottom>
{card.name}
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
)
}
}
In DataForm component, I am having a state for the form fields as:
state = {
dataForm: {
name: "",
type: this.tempData.type,
userName: "",
password: ""
},
tempData: {}
}
componentDidiMount(){
const {label} = this.props.match.params;
let temp ={};
{data.map((card) => {
if(data.label === label) {
temp =data;
}
})};
this.setState({ tempData : temp })
}
In DataForm , I want type field to have a default value as "hetero" or "homo". But there its showing an error as :
CANNOT READ PROPERTY TYPE OF UNDEFINED.
How can I get the default value in type field??
Thanks in advance.
Your component probably do not have access to this.tempData.type. Please provide full code of your components.

extract object items in object array at react template

I'm newbies in react and javascript. I try to use this below data in react template. They're object array so i want to every items in this object array print separately in HTML (react template). Anyone can help me, i have code below, please help:
const fakeData = [
{
MOP: 'MOP',
code: '#1180-xxxx',
date: '10-08-2018',
status: 'Pending Order',
},
{
MOP: 'MOP1',
code: '#1180-xxxx1',
date: '11-08-2018',
status: 'Pending Order',
},
{
MOP: 'MOP2',
code: '#1180-xxxx2',
date: '12-08-2018',
status: 'Pending Order',
},
];
export class TransactionPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = { fakeData };
}
render() {
const { classes, intl } = this.props;
return (
<Page>
<Helmet>
<title>{intl.formatMessage({ ...messages.header })}</title>
<meta
name="description"
content={<FormattedMessage {...messages.meta} />}
/>
</Helmet>
<PageContent>
<Paper>
<Grid container>
<Grid item xs={12} sm={5} md={4} lg={3}>
<List className={classes.list} disablePadding>
// show the item here
</List>
</Grid>
<Hidden xsDown>
<Grid item sm={7} md={8} lg={9}>
<Grid
container
direction="column"
spacing={16}
className={classes.details}
>
<Grid item xs={12} className={classes.center} />
<Grid item xs={12}>
<Typography variant="h6">CREDIT DEBIT</Typography>
</Grid>
<Grid item xs={12}>
<Divider />
</Grid>
<Grid item xs={12} />
</Grid>
</Grid>
</Hidden>
</Grid>
</Paper>
</PageContent>
</Page>
);
}
}
TransactionPage.propTypes = {
intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
};
const mapStateToProps = createStructuredSelector({
TransactionPage: makeSelectTransactionPage(),
});
function mapDispatchToProps(dispatch) {
return {
dispatch,
};
}
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
const withReducer = injectReducer({ key: 'TransactionPage', reducer });
const withSaga = injectSaga({ key: 'TransactionPage', saga });
export default compose(
withStyles(styles),
injectIntl,
withReducer,
withSaga,
withConnect,
)(TransactionPage);
I want this code transform as output below in the page:
<Grid container>
<Grid item xs={12} sm={5} md={4} lg={3}>
<List className={classes.list} disablePadding>
<ListItem button>
<span>MOP</span>
<span>#1180-xxxx</span>
<span>10-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
<ListItem button>
<span>MOP1</span>
<span>#1180-xxxx1</span>
<span>11-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
<ListItem button>
<span>MOP2</span>
<span>#1180-xxxx2</span>
<span>12-08-2018</span>
<span>Pending Order</span>
<ListItemSecondaryAction>
<ArrowIcon />
</ListItemSecondaryAction>
</ListItem>
</List>
</Grid>
i'm using react, how to loop them in react template.
You just create a map with JSX:
<List className={classes.list} disablePadding>
{fakeData.map((item, i) => <ListItem key={item.MOP+"_" + i} button>....</ListItem>) }
</List>
You can map it like this pseudo...
var formatted = fakeData.map((item, idx) => {
return(
<ListItem key={idx}>
<span>{item.MOP}</span>
<span>{item.code}</span>
<span>{item.date}</span>
<span>{item.status}</span>
</ListItem>
)
})
return(
<List>
{formatted}
</List>
)

Categories

Resources