I'm getting a weird TypeError in my React code
Given below is the code snippet where I am passing the components:
function Home(props) {
return (
<div className="container">
<div className="row align-items-start">
<div className="col-12 col-md m-1">
<RenderCard item={props.dish} isLoading={props.dishesLoading} errMess={props.dishesErrMess}/>
</div>
<div className="col-12 col-md m-1">
<RenderCard item={props.promotion} isLoading={props.promoLoading} errMess={props.promoErrMess} />
</div>
<div className="col-12 col-md m-1">
<RenderCard item={props.leader} isLoading={props.leadersLoading} errMess={props.leadersErrMess} />
</div>
</div>
</div>
);
}
What is even more weird is that, if I remove either the second div where I'm passing the promotions or the third div where I'm passing the leader; the code seems to work fine without showing any error and the web page is rendered.
Any explanation on why this is happening and a possible solution is much appreciated.
The code snippet of RenderCard if necessary:
function RenderCard({ item, isLoading, errMess }) {
if (isLoading) {
return (
<Loading />
);
}
else if (errMess) {
return (
<h4>{errMess}</h4>
);
}
else
return (
<FadeTransform in transformProps={{exitTransform: 'scale(0.5) translateY(-50%)'}}>
<Card>
<CardImg src={baseUrl + item.image} alt={item.name} />
<CardBody>
<CardTitle>{item.name}</CardTitle>
{item.designation ? <CardSubtitle>{item.designation}</CardSubtitle> : null}
<CardText>{item.description}</CardText>
</CardBody>
</Card>
</FadeTransform>
);
}
The error is saying item is undefined, so it cannot read a property "image" from undefined.
I'm gonna go ahead and say that one/some/all of these props is undefined
<RenderCard item={props.dish}
<RenderCard item={props.promotion}
<RenderCard item={props.leader}
function RenderCard({ item, isLoading, errMess }) {
if (isLoading) {
return (
<Loading />
);
}
else if (errMess) {
return (
<h4>{errMess}</h4>
);
}
else
return (item ? <FadeTransform in transformProps={{ exitTransform: 'scale(0.5) translateY(-50%)' }}>
<Card>
<CardImg src={baseUrl + item.image} alt={item.name} />
<CardBody>
<CardTitle>{item.name}</CardTitle>
{item.designation ? <CardSubtitle>{item.designation}</CardSubtitle> : null}
<CardText>{item.description}</CardText>
</CardBody>
</Card>
</FadeTransform> : null
);
}
Check it the item property exist and render the component or return null
Related
I create an e-commerce website with react, There is an error on redirecting between pages
Problem:
When wanted to redirect to SingleProduct Page from Category Page there's an error " Cannot read .map of undefined" but when refreshing the page, the page can be seen.
Also, the same when want to redirect to the Home page from SingleProduct Page. The code below is from the Category Page . at usequery i use isloading and iserror and isSuccess in the return function as below
const {
isLoading,
isError,
error,
data: res,
isSuccess,
} = useQuery("product", () => Axios.get(`/Product/AllProduct`));
// spinner when data loads
if (isLoading) {
return (
<Col className="text-center" md="12">
<div className="uil-reload-css reload-background mr-1 align-center">
<div className="" />
</div>
</Col>
);
}
if (isError) {
return (
<div>
<h1 className="title text-center">
{error.message}
<br />
<p className="error-msg text-center">
We';re sorry, There is an error encounter.
<br />
Please retry again after few minutes.
</p>
</h1>
</div>
);
}
{isSuccess &&
res.data.Result.map((product) => (
<Col key={product.ID} md="4" sm="4">
<Card className="card-product card-plain">
<div className="card-image">
<img
alt={product.Name}
className="img-rounded img-responsive"
src={`/api/v1/ProductFile/${encodeURIComponent(
product.ID
)}/Product/${encodeURIComponent(product.ProductImages[0])}`}
/>
</Card>
Use conditional operator before map, like this:
{isSuccess && res && res.data && res.data.Result && res.data.Result.map((product) => (
Or optional chaining:
{isSuccess && res?.data?.Result?.map((product) => (
In axios you can target the response by using res.data Maybe this is what you are missing out.
I am new to React and recently started working on it. I know that we cannot change the components properties using the props.
I want to know how can we change the properties of Component?
Below is my code:
Courses.jsx
function Courses(){
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{CourseData.map((value,index)=>{
return (
<div className="col-md-3">
<Card title={value.title} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
}
Here above i am having a Array of Data named as courseData, I am mapping it on a Card component.
Card.jsx:
function Card(props){
function handleClick(){
}
return (
<div className="card">
<div className="card-body">
<h2 className="card-title">{props.title}</h2>
{props.content}
<br/>
<button className="btn btn-danger" > {props.value}</button>
</div>
</div>
);
}
the CourseData has following properties :
courseData : [{
key,
title,
completed
content}]
I simply want that when ever the button present is card gets clicked then the completed attribute of courseData changed to some different value that is passed through the props .
I have tried a lot but not able to do .
Any help regarding this will be helpful for me .
courseData.jsx:
const notes = [{
key: 1,
title: "some Text",
completed:false,
content: "some Text"
},
{
key: 2,
title: "some Text",
completed:false,
content: "some Text"
}]
export default notes;
Add CourseData to the state of the Courses component. Then add a method to adjust the data there. Pass the method throught props that will be called when clicking button in the Card component:
function Courses() {
const [courseData, setCourseData] = useState(CourseData);
const updateCourseData = (index) => {
courseData.splice(index, 1);
setCourseData(courseData);
}
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{courseData.map((value,index)=>{
return (
<div className="col-md-3">
<Card title={value.title} updateCourseData={updateCourseData} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
}
in the Card.jsx:
<button onClick={() => props.updateCourseData(props.id)} className="btn btn-danger" > {props.value}</button>
function Courses(){
const [coursesData, setCoursesData] = useState(CourseData)
return (
<div className="courses">
<h1>Ongoing Courses</h1>
<div className="row">
{coursesData.map((value,index)=>{
return (
<div className="col-md-3">
<Card coursesData={coursesData} setCoursesData={setCoursesData} title={value.title} completed={value.completed} content={value.content} value="Resume !" key={index} id={index} />
</div>
);
})}
</div>
</div>
);
function Card({id,title,value,content,coursesData,setCoursesData }){
function handleClick(e){
e.preventDefault()
setCoursesData(coursesData => {
const data = coursesData
data.splice(id,1,{
title: title,
completed: value,
content: content,
key: id
})
return data
})
}
return (
<div className="card">
<div className="card-body">
<h2 className="card-title">{title}</h2>
{content}
<br/>
<button onClick={handleClick} className="btn btn-danger">{value}</button>
</div>
</div>
);
<div className="left">
<ReactFullpage
licenseKey='xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx'
sectionsColor={["#000000"]}
render={({ state, fullpageApi }) => {
return (
<div id="fullpage-wrapper">
{this.state.items == undefined ? '' : this.state.items.map((img,i) => (
<img className="section" key={i} src={img.image}></img>
))}
</div>
);
}}
/>
</div>
Hi, I've some issues when I am trying to fetch the data and render in ReactFullpage Component, the error says:
TypeError: Cannot read property '0' of null
Thank you, all help is welcome.
The issue here is that ReactFullPage works on the principle of finding a className section in one of the rendered elements
Now since you load your items async, initially the following content is rendered
return (
<div id="fullpage-wrapper">
{''}
</div>
);
Notice that it doesn't have a className section to it and it throws you the error
The solution here is to either wait for items to load before showing ReactFullPage
<div className="left">
{this.state.items && <ReactFullpage
licenseKey='xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx'
sectionsColor={["#000000"]}
render={({ state, fullpageApi }) => {
return (
<div id="fullpage-wrapper">
{this.state.items.map((img,i) => (
<img className="section" key={i} src={img.image}></img>
)}
</div>
);
}}
/>}
</div>
or return a dummy component to ReactFullPage
<div className="left">
<ReactFullpage
licenseKey='xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx'
sectionsColor={["#000000"]}
render={({ state, fullpageApi }) => {
return (
<div id="fullpage-wrapper">
{this.state.items == undefined ? <div className="section" /> : this.state.items.map((img,i) => (
<img className="section" key={i} src={img.image}></img>
))}
</div>
);
}}
/>
</div>
I want to render several row containing three columns each. The columns have just a Card. The way I thought I could do this is to map through the elements and create a row when the index modulus is 0 and close that row when it's the third column of the row. I've tried with if-else statements and with ternary operators. But I keep getting syntax errors.
render(){
var { isLoaded, items } = this.state;
if(!isLoaded) {
return (<div> Fetching items </div>);
}
else {
var results = items.results;
return (
<div className="App">
<div className ="container">
{ result.map ((result, i) => {
return(
{i%3===0 ?
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>);
}
{i%3===1 ?
</div>
:null}
})}
</div>
</div>
);
}
}
With this piece of code I'm getting an error in this line
{i%3===0 ?
How can I solve this?
Because, you have a unclosed <div> tag which is invalid JSX, also { in return means an object not dynamic content.
Don't forget we write JSX, not html. Each tag needs to be closed properly, because it will get converted into React.createElement(component/html tag, props, children).
To solve the problem, first prepare the array and after 3 items, just push the elements in row arrays, like this:
renderRows() {
let results = items.results;
let finalArr = [], columns = [];
result.forEach ((result, i) => {
// prepare the array
columns.push(
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
);
// after three items add a new row
if((i+1) % 3 === 0) {
finalArr.push(<div className ="row mt-4">{columns}</div>);
columns = [];
}
});
return finalArr;
}
render(){
var { isLoaded, items } = this.state;
if(!isLoaded) {
return (<div> Fetching items </div>);
} else {
return (
<div className="App">
<div className ="container">
{this.renderRows()}
</div>
</div>
);
}
}
You are getting the error, because you are not rendering a valid element each time - it is missing a closing tag when "i%3===0" resolves to true.
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
</div> // <-- this one
Also, you could just render all the cards in that one container and set the style of the card accordingly to be the width of a third of the parent container.
<div className="container">
{result.map((result, i) => {
return (
<div key={i} className="col-md-4"> // add styles for width 30%
<Card result={result} />
</div>
);
})}
</div>
And one other idea is that instead of feeding data like [1,2,3,4,5], you could reduce the array to buckets of other arrays like [[1,2,3], [4,5,6]] and render those.
<div className="container">
{result.map((row, i) => (
<div key={i} className="row mt-4">
{row.map((col, i) => (
<div key={i} className="col-md-4">
<Card result={col} />
</div>
))}
</div>
))}
</div>
P.s. don't use the index for the element key. Use something unique, like the value of the card or an id.
You are simply missing some closing brackets.
Try this,
<div className ="row mt-4">
{ result.map ((result, i) => {
return(
<React.Fragment>
{(i%3===0) ?
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
}
</React.Fragment>
)
})}
</div>
As per your code,
{ result.map ((result, i) => {
return(
{i%3===0 ?
<div className ="row mt-4">
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>
:
<div key ={i} className="col-md-4">
<Card result={result}></Card>
</div>); //You have added `);` which is cause of error. this means you are returning this much part only.
Here's how you can fix it:
render() {
const { isLoaded, items } = this.state;
if (!isLoaded) {
return (<div> Fetching items </div>);
}
const results = items.results;
return (
<div className="App">
<div className="container">
{results.map((result, i) => (
<React.Fragment>
{(i + 1) % 4 === 0 ?
(<div className="row mt-4" key={`row-${i}`}>
<div key={i} className="col-md-4">
<Card result={result} />
</div>
</div>) :
(<div key={i} className="col-md-4">
<Card result={result} />
</div>)}
{i % 3 === 1 ? <div /> : null }
</React.Fragment>
))}
</div>
</div>
);
}
I strongly suggest you to use ESLint or linter to find and fix these errors then and there. Take a look at: https://medium.com/#RossWhitehouse/setting-up-eslint-in-react-c20015ef35f7. Eslint will help you with better indentation, matching brackets, best practices and much more. Once you have set eslint, you can sort these out yourself.
Edit:
Grouping items into four and putting them under one row:
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
isLoaded: true,
items: {
results: ["1", "2", "3", "4", "5", "6", "7", "8"]
}
};
}
render() {
const { isLoaded, items } = this.state;
if (!isLoaded) {
return (<div> Fetching items </div>);
}
const results = items.results;
// Group them into sets of 4.
const grouped = results.reduce((acc, post, ind) => {
var index = parseInt(ind / 4);
acc[index]= acc[index] || [];
acc[index].push(<div key={`colmn-${index}`} className="col-md-4">{results[ind]}</div>);
return acc;
}, []);
return (
<div className="App">
<div className="container">
{grouped.map((row, i) => {
return <div className="row mt-4" key={`row-${i}`}>{row}</div>})}
</div>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById("retrospect-app"));
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.css" rel="stylesheet"/>
<div id="retrospect-app"></div>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
I have this child component:
const TableExpandedRowItem = ({ dataTitle, rowValue, cellClassProp }) => (
<div data-title={dataTitle} className={cellClassProp}>
<p>{rowValue}</p>
</div>
);
I am passing it to its parent to create an iteration:
const TableExpandedRowWrapper = ({ rowClassProp, billingItem }) => (
<div className={rowClassProp}>
{billingItem.map(key => (
<div>
<TableExpandedRowItem
dataTitle={billingItem[key].description}
rowValue={billingItem[key].description}
/>
<TableExpandedRowItem
dataTitle={billingItem[key].recurringFee}
rowValue={billingItem[key].recurringFee}
/>
</div>
))}
</div>
);
I get this error:
Uncaught TypeError: billingItem.map is not a function
Here is where I need to call it:
{rowExpanded.billingItems &&
rowExpanded.billingItems.map(item =>
rowExpanded.id === item.cancellationRequestId && (
<div className="row" key={item.id}>
// HERE
<TableExpandedRowWrapper billingItem={item.billingItem} />
...
UPDATE:
If I call the component TableExpandedRowItem directly without a the wrapper component it works as it should:
{rowExpanded.billingItems &&
rowExpanded.billingItems.map(item =>
rowExpanded.id === item.cancellationRequestId && (
<div className="row" key={item.id}>
<TableExpandedRowItem
dataTitle={item.billingItem.description}
rowValue={item.billingItem.description}
/>
<TableExpandedRowItem
dataTitle={item.billingItem.recurringFee}
rowValue={item.billingItem.recurringFee}
/>
</div>
),
)}
I want to take this to another component which is what I am attempting to do on TableExpandedRowWrapper:
<div className="row" key={item.id}>
<TableExpandedRowItem
dataTitle={item.billingItem.description}
rowValue={item.billingItem.description}
/>
<TableExpandedRowItem
dataTitle={item.billingItem.recurringFee}
rowValue={item.billingItem.recurringFee}
/>
</div>
So basically what I need is to put TableExpandedRowItem into a wrapper and call it as shown above.