JSX conditional rendering - reactjs

I'm making my first React-Redux project.
I'd like to change the structure below simply.
const PresentationalComponent = ({
params,
query
}) => {
if (query.title === undefined) {
return (
<div>
<article>
<h2>{params.title}</h2>
<hr></hr>
<p>{params.content}</p>
</article>
</div>
);
} else {
return (
<div>
<div>
<article>
<h2>{query.title}</h2>
<hr></hr>
<p>{query.content}</p>
</article>
</div>
</div>
);
}
};
export default HomeDetail;
This is what I've tried. But it occurs error.
<article>
<h2>{query.title === undefined ? {item.title} : {query.title}}</h2>
Can we make it simple?

const PresentationalComponent = ({ params, query }) => (
<div>
<article>
<h2>{query.title ? query.title : params.title}</h2>
<hr></hr>
<p>{query.title ? query.content : params.content}</p>
</article>
</div>
);

Related

Where is the missing key for my child comp?

I've been getting a "Each child in a list should have a unique key prop" error. I've read up on the documentation and put keys in, but no luck. Not sure what I'm misunderstanding!
blogPosts is imported from a context.
The ids being called as keys are unique (POSTID1, POSTID2, ...etc).
Got rid of some classnames for better readability.
const topicPosts = blogPosts.filter((post)=>post.topic.toLowerCase()===topic);
const handleLoadMore = () => {
const newIndex = articleIndex + 5 > topicPosts.length ? topicPosts.length : articleIndex + 5;
setArticleIndex(newIndex);
}
return (
<section onClick={handleOutsideClick}>
<div>
<section>
<h1>{topic}</h1>
{
topicsData.map((topicData)=> topicData.name.toLowerCase()===topic && <p key={topicData.id}>{topicData.intro}</p>)
}
</section>
<div>
<section>
<div>
{
topicPosts.slice(0,3).map((post)=>{
const { id } = post;
return (
<TopicPagePost key={id} {...post}/>
)
})
}
</div>
<div className={topicPosts.length>3 ? `subpage-articles` : `display-none`}>
{
topicPosts.slice(3,articleIndex).map((post, index)=>{
const { id } = post;
return (
<>
<TopicPagePost key={id} {...post}/>
{
index%4===0 && <div key={index} className="subpage-main-ad">
Ad placement here
</div>
}
</>
)
})
}
</div>
<button type="button" onClick={handleLoadMore}>Load more articles</button>
</section>
<aside>
<SubscribeBlock/>
<div>
Ad placement here
</div>
</aside>
</div>
</div>
</section>
)
That is because you need to add a key to the first element returned from the map, in this case <>.
To do that, you need to replace <> with a <Fragment> instead, so you can add a key directly to it:
import React, { Fragment } from "react"
{topicPosts.slice(3,articleIndex).map((post, index) => {
const { id } = post;
return (
<Fragment key={id}>
<TopicPagePost {...post}/>
{index%4===0 && (
<div className="subpage-main-ad">
Ad placement here
</div>
)}
</Fragment>
)
})}

while using map() function props.data is undefined

its shows data without map function in console
but whenever I use map function it shows props.data is undifned and also undifined in console
I have used the same code for another page and that works
const Test_Footer = (props) => {
console.log("ok", props.data)
const newvar =props.data.map((item) => {
return (
<>
<li>{item.data.id}</li>
</>
)
})
// console.log(newvar)
return (
<div>
<div class="main-content">
<footer className="footer">
<div className="review-checkbox"><input type="checkbox" /><label>Review</label></div>
<div className="question-nav">
<ul className="pagination">
{newvar}
</ul>
<button className="minimize-btn ml-10"><img src="images/minimize-btn.png" /></button>
</div>
</footer>
</div>
</div >
)
}
export default Test_Footer
const newvar = props && props.data && props.data.map((item) => {
return (
<>
<li>{item.data.id}</li>
</>
)
})

Why is my state's value is always undefined?

I've read all the question asked that similar to my problem , but it still cant's solve my issues . I'm fetching datas from an api and assign it's values into my state , the program compiled successfully but this message appears in the browser "TypeError: weatherData.main is undefined"
Here's my code
import './App.css';
import React,{useEffect,useState} from 'react';
function App() {
const [weatherData,setWeatherData] = useState({});
const [position,setPosistion] = useState({});
useEffect(()=>{
navigator.geolocation.getCurrentPosition( pos => {
setPosistion(()=>{
return {
latitude : pos.coords.latitude,
longitude : pos.coords.longitude
}
})
});
},[])
useEffect(()=>{
fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${position.latitude}&lon=${position.longitude}&units=metric&appid=a*****5`)
.then( res => res.json() )
.then( resJson => {
setWeatherData(()=>resJson)
})
},[position]);
return (
<div className="App">
<Weather weatherData={weatherData} />
</div>
);
}
const Weather = ({weatherData}) => {
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}
export default App;
the state contains
{"coord":{"lon":106.8451,"lat":-6.2146},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}],"base":"stations","main":{"temp":302.76,"feels_like":307.06,"temp_min":300.15,"temp_max":305.93,"pressure":1007,"humidity":74},"visibility":6000,"wind":{"speed":2.57,"deg":340},"clouds":{"all":40},"dt":1613038370,"sys":{"type":1,"id":9383,"country":"ID","sunrise":1612997835,"sunset":1613042198},"timezone":25200,"id":1642911,"name":"Jakarta","cod":200}
Before the data is fetched, weather is initialised to be a empty object and hence weather.main is undefined.
You should consider rendering a fallback page till weather data is fetched
const Weather = ({weatherData}) => {
if(Object.keys(weatherData).length === 0) {
return <div>{/* Somee info here or maybe a loader*/}</div>
}
return(
<React.Fragment>
<div className="location-time">
<span id="location">{weatherData.name}</span>
</div>
<div className="weather">
<span className="temp">{`${weatherData.main.temp} C`}</span>
<div className="icon"></div>
<div className="description">{weatherData.weather[0].main}</div>
<div className="low-max">{`max : ${weatherData.main.temp_max} min : ${weatherData.main.temp_min}`}</div>
<div className="feels-like">{`feels like : ${weatherData.main.feels_like}`}</div>
<button >REFRESH</button>
</div>
</React.Fragment>
)
}

Content not displayed despite present data - React

Could you tell me why my offer content is always empty ?
The "toto" is not displayed and my data are displayed because of the line "console.log(offers").
const ListProduct = (offers : any) => {
console.log(offers);
const offersDisplay = offers ? (
<div>
{ () => {
console.log("test");
offers.map((shop :any) => {
shop.offers.map((offer:any) => {
return(
<div className="card border-secondary mb-3 listMaxWidth">
<div className="card-header">{shop.name}</div>
<div className="card-body">
<img src={offer.picture} className="imgOffer"/>
<h4 className="card-title">{offer.name}</h4>
<p className="card-text">{shop.description}</p>
</div>
</div>
);
});
})
}
}
</div>
):'toto';
return(
<div>
{offersDisplay }
</div>
)
}
export default ListProduct;
I tried so many different way to write it, unfortunately can't find the right way ...
Could you help me please ?
Thanks in advance
You don't need to pass a callback function in your code
const offersDisplay = offers ? (
<div>
//this callback
{ () => {
And also you don't return from your first map.
And the last thing is that you need to include the code in your return that way it gets executed every time the offers data is changed.
You need to change your code like this
const ListProduct = (offers : any) => {
return(
<div>
{
offers && offers.length && offers.map((shop :any) => {
return shop.offers.map((offer:any) => {
return(
<div className="card border-secondary mb-3 listMaxWidth">
<div className="card-header">{shop.name}</div>
<div className="card-body">
<img src={offer.picture} className="imgOffer"/>
<h4 className="card-title">{offer.name}</h4>
<p className="card-text">{shop.description}</p>
</div>
</div>
);
});
})
}
</div>
)
}
export default ListProduct;

Force update to make functional component re-render

I'm doing pokedex (pokemon wiki stuff). I want to change my component view, when clicking on pokemon images (description lookalike). When I click on an image - nothing happens (firstly, I want at least pokemon's name to be added to the pokemonDescription array). What am I doing wrong?
let pokemonDescription = [];
const useForceUpdate = () => {
const [value, setValue] = useState(true);
return () => setValue(value => !value);
}
const forceUpdate = useForceUpdate();
const onPokemonClick = (event) => {
console.log(
"wrapper clicked, event.target - ",
event.target.getAttribute('data-name')
);
pokemonDescription = [];
pokemonDescription.push(event.target.getAttribute('data-name'));
console.log("description array -", pokemonDescription);
forceUpdate();
};
useEffect(() => {
document.querySelector(".wrapper").addEventListener("click", onPokemonClick);
...
return () => {
document.querySelector(".wrapper").removeEventListener("click", onPokemonClick);
};
}, []);
...
return (
<div className="Pokemons">
<div className="column pokemons-list">
<div className="wrapper">
{
pokemonsData.map((p, id) => (
<div className="box" key={ id }>
<img
src={ p.sprites.front_default }
alt="pokemon-img"
title={ p.name }
className="icon"
data-name={p.name}
/>
{ p.name}
<div className="container">
{ pokemonsTypes[id] }
</div>
</div>
))
}
</div>
...
</div>
<div className="column description">
{ pokemonDescription }
</div>
</div>
)
You should add pokemonDescription to your component state
const [pokemonDescription, setPokemonDescription] = useState([]);
Remove the forceUpdate function and hook, it is unnecessary.
Attach the click handlers to the elements with the data-name attribute you are trying to handle.
Map the pokemonDescription state array to renderable JSX. I simply used a div, but you should use whatever your UI design requires.
const onPokemonClick = (event) => {
setPokemonDescription(names => [
...names,
event.target.getAttribute('data-name'),
]);
};
...
return (
<div className="Pokemons">
<div className="column pokemons-list">
<div className="wrapper">
{
pokemonsData.map((p, id) => (
<div className="box" key={ id }>
<img
src={ p.sprites.front_default }
alt="pokemon-img"
title={ p.name }
className="icon"
data-name={p.name}
onClick={onPokemonClick} // <-- attach click handler to img element
/>
{ p.name}
<div className="container">
{ pokemonsTypes[id] }
</div>
</div>
))
}
</div>
...
</div>
<div className="column description">
{pokemonDescription.map(name => (
<div>{name}</div>
))}
</div>
</div>
)
Add pokemonDescription to state instead of some local variable and it will solve your issue.
Try to avoid using forceUpdate, most of the times it means only that you are doing something silly.
I don't what that useForceUpdate does , but here is how would go about adding pokemon names to description array which is a state variable in my answer
const [pokemonDescription , setPokemonDescription ] = useState(null);
const onPokemonClick = (p) => {
const tempPokemonDescription = [...pokemonDescription ];
pokemonDescription.push(p.name);
console.log("description array -", pokemonDescription);
setPokemonDescription(tempPokemonDescription )
};
...
return (
<div className="Pokemons">
<div className="column pokemons-list">
<div className="wrapper">
{
pokemonsData.map((p, id) => (
<div className="box" onClick={e=>onPokemonClick(p)} key={ id }>
<img
src={ p.sprites.front_default }
alt="pokemon-img"
title={ p.name }
className="icon"
/>
{ p.name}
<div className="container">
{ pokemonsTypes[id] }
</div>
</div>
))
}
</div>
...
</div>
<div className="column description">
{ pokemonDescription }
</div>
</div>
)

Resources