React not rendering components from if else block - reactjs

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} />
})
}

Related

Component is not being returned in nested loop

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>

Why do i have a problem rendering this 'Loading' component in react?

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

Why onClick function not return the tags, in console all good

After onClick I must render information about other users that I get from server
In console, all info is passed, but not render. Also I try simple, like ${item.name}, but nothing. That’s why I understand,
I’m doing something wrong, WHAT? thanks))
<Consumer>
{value => {
const { users_ } = value;
return (<ButtonContainer
onClick={() => {users_.forEach(item => {
return (
<React.Fragment>
<div className='col-sm-6 d-inline-flex p-4'>
<img src='${item.photo}'className='usersImg' />
<h3>`${item.name}`</h3>
<p className='p2'>`${item.position}`<br />`${item.email}`<br />`${item.phone}`</p>
</div>
</div>
</React.Fragment>
);}}</Consumer>
That’s why I wrote, no errors, nothing((

Why my this.props.data coming undefined anywhere before render function?

Data is passing from parent to child accordingly hence its showing inside render function but I am unable to use that to a async function which I need to run before the render.
If you see the data.title and data.link all showa under the render function but for some reason they are showing this error:
×
TypeError: Cannot read property 'link' of null
What can I alternatively do?
export default class Highlight extends Component {
state = {
htmlString: ''
}
fetchActivity = () => {
axios({
method: 'post',
url: 'api/singleactivity',
data: { activityLink: "http://play.fisher-price.com" + this.props.data.link }
})
.then((res) => {
this.setState({
htmlString: res.data
})
})
.catch((err) => {
console.log('There was an error fetching data', err);
})
}
componentDidMount() {
this.fetchActivity()
}
render() {
if (this.props.visibility.highlight) {
return (
<div>
<section className="card bg-info"
aria-label="Book Detail">
<div className="bg-secondary">
<h2>{this.props.data.title}</h2>
<h2>{this.props.data.link}</h2>
<h2>{this.props.data.imageLink}</h2>
</div>
<br />
<div className="row" dangerouslySetInnerHTML={{ __html: this.state.htmlString }}>
</div>
<br />
<div className="bg-warning">
{!this.props.visibility.favorites ?
<button onClick={() => this.addToFavorites()}> Favorite</button> :
<button onClick={() => this.removeFromFavorites()}> Remove</button>}
</div>
</section>
<br />
</div>
)
} else {
return null;
}
}
Well, mixing fetch calls and view code or using dangerouslySetInnerHTML apart, your prop this.props.data does not always hold a value and this is the direct source of your issue.
So surely you're using your component this way <Highlight data={stuff} ... /> you can change it to something like {stuff ? <Highlight data={stuff} ... /> : null} so the component won't be created in the first place if the input data is not ready yet.
What you can do is :
{this.props.data ? this.props.data.title : ''}
{this.props.data ? this.props.data.link: ''}

Rendering Parameterized Function Results

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>
)
})
}
}

Resources