Show nested route component in new page - reactjs

I have a nested route component which is getting displayed at the bottom of the parent component. I want to display this component in a new page. Here is my code-
CategoryList.js
class CategoryList extends Component {
state = {
categories: []
}
componentDidMount() {
fetch('http://localhost:8080/testcategory')
.then(results => {
return results.json();
}).then(data => {
this.setState({ categories: data.categories });
})
.catch(error => {
this.setState({ error: true });
});
}
categorySelectedHandler = (id) => {
this.props.history.replace('/testcategory/' + id);
}
render() {
let categories = <p style={{ textAlign: 'center' }}>Something went wrong!</p>;
if (!this.state.error) {
categories = this.state.categories.map(category => {
{this.props.children}
return (
<Table.Row key={category.id}>
<Table.Cell>{category.name}</Table.Cell>
<Table.Cell>{category.id}</Table.Cell>
<Table.Cell> <Button icon labelPosition='left' onClick={() => this.categorySelectedHandler(category.id)}>show</Button></Table.Cell>
{/* Tried this as well
<Table.Cell>
<Link to={"/category/"+category.id}>
<Button icon labelPosition='left' >Show</Button>
</Link>
</Table.Cell> */}
</Table.Row>
)
})
}
return (
<div>
<Table stackable>
<Table.Header>
<Table.Row >
<Table.HeaderCell>Name</Table.HeaderCell>
<Table.HeaderCell>ID</Table.HeaderCell>
<Table.HeaderCell>Operations</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{categories}
{this.props.children}
</Table.Body>
</Table>
<Route path={this.props.match.url + '/:id'} exact component={CategoryDetails} />
</div>
);
}
}
export default CategoryList;
CategoryDetails.js
import React, { Component } from 'react';
import './CategoryDetails.css';
class CategoryDetails extends Component {
state = { loadedCategory: null }
componentDidMount() {
this.loadData();
}
componentDidUpdate() {
this.loadData();
}
shouldComponentUpdate(nextProps, nextState) {
return nextProps.match.params.id != nextState.loadedCategory.id ;
}
loadData=() =>{
if (this.props.match.params.id) {
if (!this.state.loadedCategory || (this.state.loadedCategory && this.state.loadedCategory.id !== +this.props.match.params.id)) {
fetch('http://localhost:8080/testcategory/' + this.props.match.params.id)
.then(results => {
return results.json();
}).then(data => {
this.setState({ loadedCategory: data});
})
.catch(error => {
this.setState({ error: true });
});
}
}
}
render() {
let category = <p style={{ textAlign: 'center' }}>Please select a Post!</p>;
if (this.props.match.params.id) {
category = <p style={{ textAlign: 'center' }}>Loading...!</p>;
}
if (this.state.loadedCategory) {
category = (
<div className="CategoryDetails">
<h1>{this.state.loadedCategory.name}</h1>
<p>{this.state.loadedCategory.code}</p>
<p>{this.state.loadedCategory.id}</p>
{this.props.children}
</div>
);
}
return (category);
}
}
export default CategoryDetails;

remove CategoryDetails Route from CategoryList file and move it to the file where Route specified for CategoryList
<Route path={this.props.match.url + '/:id'} exact component={CategoryDetails} />
<Route path={this.props.match.url + '/:dummyid'} exact component={CategoryList} />

Related

I am not able to change state and pass props

I have the stake component that is rendered 4 times in the parent class component. I am trying to pass valueNewStake as prop to its parent component and group all the inputs in one common array (see allStakes). For a reason I am not able to change the state and also the dom does not render the button next to the component. Can anyone explain me why it is happening as I am new in react. Thanks
import React, { Component } from 'react';
import Stake from './stake';
class FetchRandomBet extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
bet: null,
value: this.props.value,
allStakes: ['']
};
}
async componentDidMount() {
const url = "http://localhost:4000/";
const response = await fetch(url);
const data = await response.json();
this.setState({
loading: false,
bet: data.bets,
});
}
render() {
const { valueProp: value } = this.props;
const { bet, loading } = this.state;
if (loading) {
return <div>loading..</div>;
}
if (!bet) {
return <div>did not get data</div>;
}
return (
< div >
{
loading || !bet ? (
<div>loading..</div>
) : value === 0 ? (
<div className="bet-list">
<ol>
<p>NAME</p>
{
bet.map(post => (
<li key={post.id}>
{post.name}
</li>
))
}
</ol>
<ul>
<p>ODDS</p>
{
bet.map(post => (
<li key={post.id}>
{post.odds[4].oddsDecimal}
<div className="stake-margin">
<Stake
allStakes={this.props.valueNewStake}
onChange={() => { this.setState({ allStakes: [...this.props.valueNewStake] }) }}
>
<button>ok</button>
</Stake>
</div>
</li>
))
}
</ul>
</div>
import React, { useState } from 'react';
import CurrencyInput from 'react-currency-input-field';
function Stake() {
const [newStake, setStake] = useState(['']);
const changeStake = (e) => {
setStake(e.target.value)
}
return (
<>
<CurrencyInput
onChange={changeStake}
valueNewStake={newStake}
style={{
marginLeft: "40px",
width: "50px"
}}
placeholder="Stake"
decimalScale={2}
prefix="£"
/>
{newStake}
</>
);
}
export default Stake;
You're not passing your props to your Stake component
function Stake({ allStakes, onChange }) {
// do something with your props here
const [newStake, setStake] = useState(['']);
const changeStake = (e) => {
onChange()
setStake(e.target.value)
}
return (
<>
<CurrencyInput
onChange={changeStake}
valueNewStake={newStake}
style={{
marginLeft: "40px",
width: "50px"
}}
placeholder="Stake"
decimalScale={2}
prefix="£"
/>
{newStake}
</>
);
}

Connected component doesn't re-render after store changed from another connected component

I am having a problem related to redux.
I have 2 connected components which are:
avatar situated in the navbar which is always visible
profile which is responsible for changing the avatar image in the store
if I am right, when the store change, any connected component will re-render if needed.
In my case, when the action UPDATE_CURRENT_USER update the avatar image, the navbar avatar doesn't get the new image only after I change route or reload page.
I found a solution but many people say it's a hack,
I have put a listener on store changes in the main component and did forceUpdate()
componentDidMount() {
store.subscribe(res => this.forceUpdate());
}
and I don't want to use it since connected components are supposed to re-render on store changes.
user actions:
export const getCurrentUser = () => dispatch => {
axios.get("user").then(user => {
dispatch({
type: GET_CURRENT_USER,
payload: user.data
});
});
};
export const updateCurrentUser = user => dispatch => {
dispatch({
type: UPDATE_CURRENT_USER,
payload: user
})
}
user reducer
const initialState = {
user: {}
}
export default function (state = initialState, action) {
switch (action.type) {
case GET_CURRENT_USER:
return { ...state, user: action.payload };
case UPDATE_CURRENT_USER:
return { ...state, user: action.payload }
default:
return state;
}
}
profile component
class Profile extends Component {
render() {
const { currentUser, updateCurrentUser } = this.props;
return (
<div id="profile-container">
<ProfileSider
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
<ProfileContent
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ updateCurrentUser }
)(Profile);
profile sidebar child of profile
class ProfileSider extends Component {
state = { uploading: false };
triggerAvatarInput() {
$("#avatarInput").click();
}
handleChange = async event => {
this.setState({ ...this.state, uploading: true });
const avatarFormData = new FormData();
avatarFormData.append("file", event.target.files[0]);
axios
.post("uploadFile", avatarFormData)
.then(res => {
const avatarURIFormData = new FormData();
avatarURIFormData.append("avatar", res.data.fileDownloadUri);
axios
.put("user/update", avatarURIFormData)
.then(res => {
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
this.setState({
...this.state,
uploading: false,
avatar: currentUser.avatar
});
message.success("Avatar updated successfully", 3);
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Updating avatar failed!", 3);
});
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Uploading avatar failed!", 3);
});
};
render() {
const { uploading } = this.state;
const { currentUser } = this.props;
return (
<div id="profile-sider">
<div id="profile-sider-info">
<div id="profile-sider-info-avatar">
<div className="container">
<div
className="overlay-uploading"
className={
uploading ? "overlay-uploading" : "overlay-uploading hidden"
}
>
<Icon type="loading" style={{ fontSize: 50, color: "#FFF" }} />
</div>
<div className="overlay" />
<div className="overlay-text" onClick={this.triggerAvatarInput}>
<Icon type="camera" style={{ fontSize: 20 }} />
<span>Update</span>
</div>
<div
className="avatar"
style={{
backgroundImage: "url(" + currentUser.avatar + ")"
}}
></div>
<input
onChange={this.handleChange}
type="file"
accept="image/png, image/jpeg, image/jpg"
id="avatarInput"
/>
</div>
</div>
<h2 style={{ marginTop: 20, textAlign: "center" }}>
{currentUser.fullName}
</h2>
<h4 style={{ textAlign: "center" }}>{currentUser.email}</h4>
</div>
<div id="profile-sider-actions">
<div className="profile-sider-actions-item">
<Link to="/profile/courses" style={{ transition: 0 }}>
<Button type="primary" id="courses-btn">
<Icon type="read" style={{ marginRight: 15 }} />
My Courses
</Button>
</Link>
</div>
<div className="profile-sider-actions-item">
<Link to="/profile/update">
<Button type="primary" id="update-infos-btn">
<Icon type="sync" style={{ marginRight: 15 }} />
Update Infos
</Button>
</Link>
</div>
</div>
</div>
);
}
}
export default ProfileSider;
avatar component situated in navbar
class ProfileAvatar extends Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
this.handleOutsideClick = this.handleOutsideClick.bind(this);
this.state = {
showProfileDropdown: false
};
}
componentDidMount() {
this.props.getCurrentUser();
}
handleLogout = async () => {
try {
await auth.logout();
this.props.onLogout();
notification["success"]({
message: "You have been successfully logged out!"
});
} catch (ex) {}
};
handleClick() {
if (!this.state.showProfileDropdown) {
// attach/remove event handler
document.addEventListener("click", this.handleOutsideClick, false);
} else {
document.removeEventListener("click", this.handleOutsideClick, false);
}
this.setState(prevState => ({
showProfileDropdown: !prevState.showProfileDropdown
}));
}
handleOutsideClick(e) {
// ignore clicks on the component itself
if (this.element && this.element.contains(e.target)) {
return;
}
this.handleClick();
}
render() {
const { currentUser } = this.props;
return (
<div
className="profile-avatar"
ref={element => {
this.element = element;
}}
>
<Avatar
onClick={this.handleClick}
size="large"
style={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
src={currentUser.avatar}
>
{currentUser.fullName ? currentUser.fullName.charAt(0) : null}
</Avatar>
{this.state.showProfileDropdown && (
<div className="profile-dropdown-list">
<List
className="dropdown_list dropdown-shadow "
size="small"
style={{ width: "150px" }}
bordered
itemLayout="vertical"
dataSource={[
<Link to="/profile/update" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="user" /> My Profile
</List.Item>
</Link>,
<Link to="/profile/courses" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="container" /> My
Courses
</List.Item>
</Link>,
<List.Item className="list-item">
<Icon className="profile-icons" type="question-circle" /> Ask
for Help
</List.Item>,
<List.Item className="list-item" onClick={this.handleLogout}>
<Icon className="profile-icons" type="logout" /> Log out
</List.Item>
]}
renderItem={item => item}
/>
</div>
)}
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ getCurrentUser }
)(ProfileAvatar);
image: https://imge.to/i/vywTNj
There are two problems here:
You are mutating the existing object from the store
You are sending that exact same user object back into the store when you dispatch the action.
Specifically, these lines are the cause:
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
currentUser is the user object that's already in the Redux store. This code mutates the object, and inserts it back into the store.
That results in the connected component thinking nothing has actually changed.
The shortest way to fix this is to create a new user object, and insert that:
const {currentUser} = this.props;
const updatedUser = {...currentUser, avatar: res.data.avatar};
this.props.updateCurrentUser(updatedUser);
To avoid this in the future, I strongly encourage you to use the configureStore function from our Redux Starter Kit package, which detects mutations and will throw errors if you mutate.

How to update data between components?

Image of the consoleI'm trying to create a website using the movie DB API. I've created a carousel with some movies and want to open a new page with comprehensive information about a movie by clicking on the movie poster. I'm using componentDidMount to fetch data in one component to create a UI and I pass a movie ID to another component where I use componentWillReceiveProps to fetch another data by using the ID. It worked until I started using state, so now it shows two arrays in the console before I click on a movie poster and when I click on a poster it shows an array and loads a movie data from API then if I click on another poster it loads two different objects with the previous and current movie. I found out that componentWillReceiveProps is dangerous to use but componentDidUpdate works in the same manner.
The main idea is when a user clicks on a poster it gets its id and sends it to another component where the id goes to a link
with complete information about the movie. Are there any patterns to achieve it?
class Data extends Component {
state = {
movies: [],
movieId: null
};
onClick = e => {
this.setState({
movieId: e.target.id
});
console.log(e.target.id);
};
componentDidMount() {
fetch(url)
.then(res => res.json())
.then(data => {
let movies = data.results.map(item => {
return (
<Link to="/movieInfo">
<div className="overlay" onClick={this.onClick}>
<img
src=
{`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
alt={item.title}
id={item.id}
/>
</div>
</Link>
);
});
this.setState({
movies: movies
});
})
.catch(err => console.log(err));
}
render() {
const { movies, movieId } = this.state;
return (
<div className="carousel">
<Slider movie={movies} />
<div className="notShow">
<AdditionalInfo id={movieId} />
</div>
</div>
);
}
}
class AdditionalInfo extends Component {
state = {
movie: []
};
componentDidUpdate(prevProps) {
if (prevProps.id !== null && prevProps.id !== this.props.id) {
fetch(
`https://api.themoviedb.org/3/movie/${
prevProps.id
}?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
)
.then(res => res.json())
.then(data =>
this.setState({
movie: data
})
);
} else {
return null;
}
}
render() {
const { movie } = this.state;
console.log(movie);
return (
<div className="movieInfo-container">
{/* <section className="title" />
<section className="cast">{movie.id}</section> */}
work
</div>
);
}
}
let movieArr = [];
class Slider extends Component {
state = {
currentIndex: 0,
translateValue: 0
};
createNestedArr = () => {
while (this.props.movie.length) {
movieArr.push(this.props.movie.splice(0, 5));
}
return movieArr.map((item, i) => {
return <Slide key={i} movieGroup={item} />;
});
};
nextPic = () => {
if (this.state.currentIndex === movieArr.length - 1) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
}
this.setState(prevState => ({
currentIndex: prevState.currentIndex + 1,
translateValue: prevState.translateValue - this.slideWidth()
}));
};
prevPic = () => {
if (this.state.currentIndex === movieArr.length + 1) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
} else if (this.state.currentIndex === 0) {
return this.setState({
currentIndex: 0,
translateValue: 0
});
}
this.setState(prevState => ({
currentIndex: prevState.currentIndex - 1,
translateValue: prevState.translateValue + this.slideWidth()
}));
};
slideWidth = () => {
return document.querySelector(".new-releases-slide").clientWidth;
};
render() {
return (
<React.Fragment>
<div
className="movie-carousel"
style={{
transform: `translateX(${this.state.translateValue}px)`,
transition: "transform ease-out 0.45s"
}}
>
{this.createNestedArr()}
</div>
<LeftArrow prevPic={this.prevPic} />
<RightArrow nextPic={this.nextPic} />
</React.Fragment>
);
}
}
const Slide = props => {
const { movieGroup } = props;
return <div className="new-releases-slide">{movieGroup}</div>;
};
Use componentDidMount in your AdditionalIno component. You need to pass the id of the clicked movie to MovieInfo component. This <Link to="/movieInfo"> needs to <Link to={'/movieInfo/${item.id}'}> and in your MovieInfo component access the id using const { id } = this.props.match.params;.
import React, { Component } from 'react';
import Loader from "react-loader-spinner";
class AdditionalInfo extends Component {
state = {
movie: [],
isLoading: true,
};
componentDidMount = () => {
const { id } = this.props;
if (!id) {
return;
}
fetch(
`https://api.themoviedb.org/3/movie/${id}?api_key=81f382d33088c6d52099a62eab51d967&language=en-US`
)
.then(res => res.json())
.then(data =>
this.setState({
movie: data,
isLoading: false,
})
);
}
render() {
const { movie } = this.state;
return (
<div className="movieInfo-container">
{this.state.isLoading
? <Loader type="Puff" color="#00BFFF" height="100" width="100" />
: <div><section className="title" />
<h1>{movie.title}</h1>
<section className="cast">ID: {movie.id}</section>
<h2>Overview</h2>
<p>{movie.overview}</p></div>
}
</div>
);
}
}
export default AdditionalInfo;
then in your Data component change your componentDidMount
componentDidMount = () => {
fetch(url)
.then(res => res.json())
.then(data => {
let movies = data.results.map(item => {
return (
<Link to={`/movieInfo/${item.id}`}>
<div className="overlay" onClick={this.onClick}>
<img
src=
{`https://image.tmdb.org/t/p/w500/${item.poster_path}`}
alt={item.title}
id={item.id}
/>
</div>
</Link>
);
});
this.setState({
movies: movies
});
})
.catch(err => console.log(err));
}
In your MovieInfo do something like
class MovieInfo extends Component {
render() {
const {id} = this.props.match.params;
return (
<div>
<AdditionalInfo id={id} />
</div>
)
}
}
Your router should be like
<Route path="/movieInfo/:id" exact component={MovieInfo} />
Working Demo

Child component not updating in React

Help! My child component is not updating in my react app!
I want to bring cartNumber to the page component which then is passed onto header component but the number doesn't even show up!
Parent component
class Shop extends Component {
constructor(props) {
super(props);
this.state = {
merchants: [],
error: null,
loading: true,
order: []
};
}
componentWillMount() {
Meteor.call("merchants.getMerchants", (error, response) => {
if (error) {
this.setState(() => ({ error: error }));
} else {
this.setState(() => ({ merchants: response }));
}
});
}
componentDidMount() {
setTimeout(() => this.setState({ loading: false }), 800); // simulates loading of data
}
goBack = () => this.props.history.push("/");
goCart = () => {
try {
Orders.insert(this.state.order), this.props.history.push("/cart");
} catch (error) {
throw new Meteor.Error("there was an error", error);
}
};
onAddToCart(cartItem) {
let { order } = this.state;
order.push(cartItem);
console.log(order.length);
}
render() {
const { loading } = this.state;
const { merchants, error } = this.state;
const { data } = this.state;
const { order } = this.state;
const getProductsFromMerchant = ({ products, brands }) =>
products.map(({ belongsToBrand, ...product }) => ({
...product,
brand: brands[belongsToBrand]
}));
const products = merchants.reduce(
(acc, merchant) => [...acc, ...getProductsFromMerchant(merchant)],
[]
);
if (loading) {
return (
<Page
pageTitle="Shop"
history
goBack={this.goBack}
goCart={this.goCart}
>
<div className="loading-page">
<i
className="fa fa-spinner fa-spin fa-3x fa-fw"
aria-hidden="true"
/>
<br /> <br />
<span>Loading...</span>
</div>
</Page>
);
}
return (
<Page
pageTitle="Shop"
history
goBack={this.goBack}
goCart={this.goCart}
cartNumber={order.length}
>
<div className="shop-page">
{products.map(({ id, ...product }) =>
<Product
{...product}
key={id}
history
onAddToCart={this.onAddToCart.bind(this)}
/>
)}
</div>
</Page>
);
}
}
export default Shop;
Here is the page component which contains the header component
export const Page = ({
children,
pageTitle,
history,
goBack,
goCart,
cartNumber
}) =>
<div className="page">
<Header goBack={goBack} goCart={goCart} history cartNumber>
{pageTitle}
</Header>
<main>
<MuiThemeProvider>
{children}
</MuiThemeProvider>
</main>
<Footer />
</div>;
export default Page;
And Finally this is the header where I want to bring the cartNumber into.
const Header = ({ children, goBack, goCart, cartNumber, pageTitle }) =>
<header>
<button onClick={goBack} className="back-button">
{/* Image added here to show image inclusion, prefer inline-SVG. */}
<img alt="Back" src={`/icon/header/back-white.svg`} />
</button>
<h1>
{children}
</h1>
<div className="right-content">
( {cartNumber} )
<i
className="fa fa-shopping-cart fa-2x"
aria-hidden="true"
onClick={goCart}
/>
</div>
</header>;
export default withRouter(Header);
You're passing cartNumber as a boolean:
<Header goBack={goBack} goCart={goCart} history cartNumber>
Pass it as a value:
<Header goBack={goBack} goCart={goCart} history={history} cartNumber={cartNumber}>

Async issue with React render happening before set.state happens

I am having some trouble dealing with an async issue. The render is happening before the state is set at getStepContent(0) causing me to lose access to the state's values when I pass it down a component (CartInfo). Any ideas?
class Cart extends PureComponent {
constructor(props) {
super(props);
this.state = {
order: [],
error: null,
finished: false,
stepIndex: 0
};
}
componentWillMount() {
Meteor.call("orders.getLastOrder", (error, response) => {
if (error) {
this.setState(() => ({ error: error }));
console.log(error);
} else {
this.setState(() => ({ order: response }));
console.log(this.state.order);
}
});
}
goBack = () => this.props.history.push("/shop");
goCart = () => this.props.history.push("/cart");
handleNext = () => {
const { stepIndex } = this.state;
this.setState({
stepIndex: stepIndex + 1,
finished: stepIndex >= 2
});
};
handlePrev = () => {
const { stepIndex } = this.state;
if (stepIndex > 0) {
this.setState({ stepIndex: stepIndex - 1 });
}
};
getStepContent(stepIndex) {
let { order } = this.state;
switch (stepIndex) {
case 0:
while (!order) {
return getStepContent(0);
}
return <CartInfo CartInfo={order} />;
case 1:
return "What is an ad group anyways?";
case 2:
return "This is the bit I really care about!";
default:
return "You're a long way from home sonny jim!";
}
}
render() {
const { finished, stepIndex, order } = this.state;
const contentStyle = { margin: "0 16px" };
return (
<CartPage pageTitle="Cart" history goBack={this.goBack}>
<div className="CartHomePage">
<div style={{ width: "100%", maxWidth: 700, margin: "auto" }}>
<Stepper activeStep={stepIndex}>
<Step>
<StepLabel>Confirm your order</StepLabel>
</Step>
<Step>
<StepLabel>Where should we send it to?</StepLabel>
</Step>
<Step>
<StepLabel>Enjoy!</StepLabel>
</Step>
</Stepper>
<div style={contentStyle}>
{finished
? <p>
<a
href="#"
onClick={event => {
event.preventDefault();
this.setState({ stepIndex: 0, finished: false });
}}
>
Click here
</a>{" "}
to reset the example.
</p>
: <div>
{this.getStepContent(stepIndex)}
<div style={{ marginTop: 12 }}>
<FlatButton
label="Back"
disabled={stepIndex === 0}
onClick={this.handlePrev}
style={{ marginRight: 12 }}
/>
<RaisedButton
label={stepIndex === 2 ? "Finish" : "Next"}
primary={true}
onClick={this.handleNext}
/>
</div>
</div>}
</div>
</div>
<div>
{/* {order.map((item, i) => <div key={i}> {item.name}
{item.price} {item.quantity}</div>)} */}
{/* {this.state.order[0]} */}
</div>
</div>
</CartPage>
);
}
}
export default Cart;
This is the component I am passing it on to
import React from "react";
import { withRouter } from "react-router";
const CartInfo = ({ CartInfo }) =>
<div>
{CartInfo[0].name}
</div>;
export default withRouter(CartInfo);
This is the error code I am currently getting "CartInfo.jsx:6 Uncaught TypeError: Cannot read property 'name' of undefined at CartInfo"
It looks like you are trying to access CartInfo[0].name before the data has been fetched, which throws an error. You can change CartInfo component to something like this:
const CartInfo = ({ CartInfo }) => {
if (CartInfo[0]) {
return(
<div>
{CartInfo[0].name}
</div>;
);
}
}
This way the component will return null, then when the order data is fetched it will rerender and CartInfo[0] will not be undefined.
Another way to do this would be to use lodash _.get which returns undefined instead of throwing an error when you try to access properties of undefined.

Resources