I have a function that I am using to check if there are results from a page load and if there are, then map the array and return a component and if there aren't then return a string stating there are no results. At the moment I have been able to write the function without any issue, but I can't seem to get return statement to load. Am I following the right path to returning the components or is there a better method?
The console logs return the correct info, but everything in the return() isn't appearing in the view.
export default class BlogKanbanLayout extends React.Component {
constructor(props) {
super(props);
this.resultsCheck = this.resultsCheck.bind(this);
}
resultsCheck(blogs, user) {
console.log("resultsCheck")
console.log(blogs)
console.log(blogs.length)
if(blogs.length === 0) {
<p>There are no results for your filter criteria.</p>
} else {
console.log("There are blog results")
console.log(blogs)
console.log(user)
blogs.map((blog, index) => {
console.log("blog map")
console.log(blog)
return (
<div className="row">
<p>This is a test></p>
<BlogKanbanCard {...blog} key={blog.blogIdHash} user={user} />
</div>
)
})
}
}
render() {
return (
<div className="col-md-12">
{this.resultsCheck(this.props.negativeBlogs, this.props.user)}
</div>
)
}
}
In your resultsCheck you forgot to return the result of your mapping.
Also, the key used in the map function needs to be given to parent element, which here is your div.
And using conditional rendering you can reduce your entire component to the following code for te exact same result :
export default class BlogKanbanLayout extends React.Component {
render() {
const { negativeBlogs, user } = this.props
return (
<div className="col-md-12">
{negativeBlogs.length ?
negativeBlogs.map(blog =>
<div className="row" key={blog.blogIdHash}>
<p>This is a test></p>
<BlogKanbanCard {...blog} key={blog.blogIdHash} user={user} />
</div>
)
:
<p>There are no results for your filter criteria.</p>
}
</div>
)
}
}
And since you are not using the state of your component you could even optimize it to a stateless one :
const BlogKanbanLayout = ({ negativeBlogs, user }) =>
<div className="col-md-12">
{negativeBlogs.length ?
negativeBlogs.map(blog =>
<div className="row" key={blog.blogIdHash}>
<p>This is a test></p>
<BlogKanbanCard {...blog} key={blog.blogIdHash} user={user} />
</div>
)
:
<p>There are no results for your filter criteria.</p>
}
</div>
You resultsCheck method need to return something, so you need to add the return statement before the two results
resultsCheck(blogs, user) {
console.log("resultsCheck")
console.log(blogs)
console.log(blogs.length)
if(blogs.length === 0) {
return <p>There are no results for your filter criteria.</p>
} else {
console.log("There are blog results")
console.log(blogs)
console.log(user)
return blogs.map((blog, index) => {
console.log("blog map")
console.log(blog)
return (
<div className="row">
<p>This is a test></p>
<BlogKanbanCard {...blog} key={blog.blogIdHash} user={user} />
</div>
)
})
}
}
Related
I am trying to render the child component inside a nested loop. However it is not being render in the second loop(red tick). Although it is rendered normally in the first loop (blue tick). Kindly highlight why is it no rendered in the second loop.
https://i.stack.imgur.com/LFiKU.png
Codesandbox Link : https://codesandbox.io/s/competent-nova-u9rzuh?file=/src/parent.js
import React from "react";
import ProductFeaturesCards from "./ProductFeaturesCards.js";
import { Products } from "../ProductsData.js";
const ProductFeatures = ({ className = "", id }) => {
return (
<section id='product-features' className={`${className}`}>
<div className='container'>
<div className='row d-flex justify-content-center'>
<div className='col-lg-12 col-md-12 col-sm-12 col-12 py70'>
<p className='features-title'>Product Features</p>
</div>
</div>
<div className='row'>
{Products.forEach((item, i) => {
if (item.id === id) {
// return <ProductFeaturesCards data={item} key={i} />;
Object.values(item.Product_features[0]).map((feature, index) => {
console.log("ProductFeaturesCards:", feature);
return <ProductFeaturesCards data={feature} key={index} />;
});
}
})}
</div>
</div>
</section>
);
};
export default ProductFeatures;
Can you try this. Not sure if this will work
if (item.id === id) {
// return <ProductFeaturesCards data={item} key={i} />;
return Object.values(item.Product_features[0]).map((feature, index) => {
console.log("ProductFeaturesCards:", feature);
return <ProductFeaturesCards data={feature} key={index} />;
});
}
The first mistake you did was using forEach. forEach will mutate the data and will not return anything. So, Instead you need to use map which doesn't mutate and returns the result.
The 2nd mistake is the return statement not added inside the if condition for the map. So, it never gets returned and hence your first map will not receive the value.
After this you should be able to run it.
<div className="row">
{Products.map((item) => { // replaced forEach with map
if (item.id === id) {
return Object.values(item.Product_features[0]).map( // return added
(feature, index) => {
return <Card data={feature} key={index} />;
}
);
}
})}
</div>
I have 2 components which use the same data which I am fetching from a json-server.
One component uses the data as shown below:
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.dishErrMess} />
</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.leaderLoading}
errMess={props.leaderErrMess} />
</div>
</div>
</div>
);}
The other component uses the data as shown below:
const leaders = props.leaders.map((leader) => {
return (
<RenderLeader leader={leader} isLoading={props.isLoading}
errMess={props.errMess} />
);
});
Both the RenderLeader and RenderCard components have a similar structure with an if-else loop to display loading animation or error messages along with the actual content.
function RenderLeader({ leader, isLoading, errMess }) {
if (isLoading) {
return (
<Loading />
);
}
else if (errMess) {
return (
<h4>{errMess}</h4>
);
}
else
return (CONTENT)
The problem is that the loading animation and the error message are being displayed for the Home component but NOT for the other component which has exactly similar structure. Moreover, the data is being actually fetched for the second component, its just that it wont display the loading animation and error messages. What is wrong with this ?
Edit
This is how i invoke them both:
<Home
dish={this.props.dishes.dishes.filter((dish) => dish.featured)[0]}
dishesLoading={this.props.dishes.isLoading}
dishErrMess={this.props.dishes.errMess}
promotion={this.props.promotions.promotions.filter((promo) => promo.featured)[0]}
promoLoading={this.props.promotions.isLoading}
promoErrMess={this.props.promotions.errMess}
leader={this.props.leaders.leaders.filter((leader) => leader.featured)[0]}
leaderLoading={this.props.leaders.isLoading}
leaderErrMess={this.props.leaders.errMess}
/>
<Route path='/aboutus' component={() => <About leaders={this.props.leaders.leaders}
isLoading={this.props.leaders.isLoading}
errMess={this.props.leaders.errMess} />} />
Home Component works fine since it renders individual cards. Whereas for the below structure,
const leaders = props.leaders.map((leader) => {
return (
<RenderLeader leader={leader} isLoading={props.isLoading}
errMess={props.errMess} />
);
});
if props.leaders is empty, it cannot iterate and hence RenderLeader will never get called. Hence when props.isLoading is true, the props.leaders will be empty and the above arrow function will return nothing. And once the props.leaders is populated, the above function gets called, but props.isLoading will already be set to false.
That is why the loading icon or the error message was not displayed.
You can modify the calling as,
<div className="col-12">
<Media list>
<RenderLeaderList leaders={props.leaders} isLoading=
{props.leadersLoading} errMess={props.leadersErrMess}/>
</Media>
</div>
and create a new function called RenderLeaderList like;
function RenderLeaderList({leaders, isLoading, errMess})
{
if(isLoading)
{
return(
<Loading />
);
}
else if(errMess)
{
return(
<h4>{errMess}</h4>
);
}
else{
if(leaders!=null)
{
const leaders_map = leaders.map((leader) => {
return(
<div key={leader.id} className="col-12 mt-5">
<RenderLeader leader={leader}/>
</div>
);
});
return (
<div>
{leaders_map}
</div>
);
}
}
}
to make it work.
Hope it helps! :D
I would like to show mapped posts from an API inside the OwlCarousel component (import OwlCarousel from 'react-owl-carousel') the code works just fine, but only outside the OwlCarousel component. You can test on this CodeSandbox https://codesandbox.io/s/friendly-rhodes-bv5ot, the code works when you remove the OwlCarousel tag.
renderPost = () => {
return this.state.posts
? this.state.posts.map(data => (
<div key={data.id} className="item">
<div className="heading">{data.subject}</div>
<div className="content">{data.message}</div>
</div>
))
: "Loading...";
};
render() {
return (
<div className="container">
<OwlCarousel className="owl-container owl-theme">
{this.renderPost()}
</OwlCarousel>
</div>
);
}
The code works only when i put the function outside the OwlCarousel component, i think it has something to do with scopes!
render() {
return (
<div className="container">
{this.renderPost()}
</div>
);
}
Try with following code
renderPost = () => {
return (
<div>
{this.state.posts
? this.state.posts.map(data => (
<div key={data.id} className="item">
<div className="heading">{data.subject}</div>
<div className="content">{data.message}</div>
</div>
))
: "Loading..."}
</div>
)
};
And In your render of the Component, you can do same as you have already done,
{this.renderPost()}
I'm trying to access object keys using props as an index but it's not working. Error: Objects are not valid as a React child (found: object with keys {id, name, img_url, location}). If you meant to render a collection of children, use an array instead.
I am new to React so I appreciate any help.
My code:
class ExpandCard extends React.Component {
render() {
const props = this.props;
const profiles = props.profiles;
return(
<>
<div className="">
{profiles[props.active]}
</div>
</>
);
}
}
class App extends React.Component {
state = {
profiles: testData,
active: null,
}
getActive = (dataFromCard) => {
console.log('the magic number is', dataFromCard);
this.setState({active: dataFromCard});
}
render() {
return (
<div>
<div className="wrapper">
<header>
<div className="logo">LOGO</div>
</header>
<Form />
<div className="cards">
<div className="card-list">
{this.state.profiles.map(profile => <Card key={profile.id} {...profile} activeCard={this.getActive} />)}
</div>
<div className="expand-card">
<ExpandCard active={this.state.active} profiles={this.state.profiles} />
</div>
</div>
</div>
</div>
);
}
}
It looks like {profiles[props.active]} returns an object that looks like this:
{ id, name, img_url, location }
You can't return an object from a React component, maybe you meant to return {profiles[props.active].name}?
The if/else statement is working. I have put console logs and debuggers in both parts of the conditionals. It hits each when it's supposed to. But the components are not being rendered. Here is the relevant code.
handleUsers() {
this.props.users.map((user, i) => {
console.log(user, 'User')
return <User {...user} key={user.name}/>
})
}
handleVideos() {
this.props.videos.map((video,index) => {
return <Video videoId={this.handleModalPlay.bind(this)}
key={index} {...video} />
})
}
render(){
return(
<div className='main-body'>
<div className='cards'>
{this.props.videos.length === 0
? this.handleUsers()
: this.handleVideos()}
</div>
Previously, before trying to display other users, I had this piece of code and it would return and render as expected.
render(){
return(
<div className='main-body'>
<div className='cards'>
{this.props.videos.map((video,index) => {
return <Video videoId={this.handleModalPlay.bind(this)}
key={index} {...video} />
})}
</div>
I'm not really sure why the components stopped rendering when the debuggers and console logs are showing that it's getting into the appropriate functions.
You are not returning anything from handleUsers and handleVideos functions. Put a return statement
handleUsers() {
return this.props.users.map((user, i) => {
console.log(user, 'User')
return <User {...user} key={user.name}/>
})
}
handleVideos() {
return this.props.videos.map((video,index) => {
return <Video videoId={this.handleModalPlay.bind(this)}
key={index} {...video} />
})
}