In React how do I use a conditional with rendering? - javascript

I have a simple notification window, and as notifications are accepted/declined I remove the object from the notifications array.
This is my bit of code for handling displaying messages:
render: function() {
return (
<div className="chatwindowheight">
<div className="row">
<div className="large-12 columns">
<div className="large-8 columns">
<p className="thin partyHeader">Party <i className="fa fa-minus-square-o"></i></p>
</div>
<div className="large-4 columns">
<i className="fa fa-users pull-right"></i>
</div>
</div>
</div>
<div className="row chatwindowheight">
<div className="large-12 small-12 columns chatwindow" id="scrolldown">
<br/>
{
this.state.messages.map((message, i) => {
return (
<MessageComponent key={i}
username={message.username}
message={message.message}
whos={message.classed} />
);
})
}
</div>
</div>
<ChatSendComponent onChatSubmit={this.handleChatSubmit}/>
</div>
)
}
What I want is to have something like
if (this.state.messages.length === 0) {
return (
<p>You have no new notifications.</p>
)
}
but when I try to wrap something like that around the current loop, it tells me that if is an error. New to React so just trying to understand the best method for approaching this. Thanks!

There are some various resolve your problem:
1.
{ this.state.messages.length > 0 ?
this.state.messages.map((message, i) => {
return (
<MessageComponent key={i}
username={message.username}
message={message.message}
whos={message.classed} />
);
}) : 'You have messages'
}
Remove you map up to render function and prepare your data there:
function render() {
var message='';
if (this.state.messages.length) {
}
}
<b>{message}</b>

Related

render specific text based on Conditional statement

I have the following JSON
{"location":"2034","type":"Residential","price":400000,"address":"123 Fake Street","suburb":"Maroubra","historical_DAs":0,"description":"Residential","property_ID":1},
{"location":"2036","type":"Commercial","price":475000,"address":"123 Fake Street","suburb":"Coogee","historical_DAs":10,"description":"Government","property_ID":2},
{"location":"2035","type":"Food & Bev","price":56000,"address":"123 Fake Street","suburb":"Clovelly","historical_DAs":3,"description":"Residential","property_ID":3},
{"location":"2031","type":"Education","price":69070,"address":"123 Fake Street","suburb":"Randwick","historical_DAs":7,"description":"Government","property_ID":4},
{"location":"2036","type":"Education","price":69070,"address":"123 Fake Street","suburb":"Randwick","historical_DAs":7,"description":"Government","property_ID":5}
I want to render different images based upon the description field (currently trying to just get text to render correctly atm.)
What I have tried so far:
function TypeImages({ description }) {
function Residential(props) {
return <div>
<h1>Image 1</h1>
</div>;
}
function Government(props) {
return <div>
<h1>Image 2 </h1>
</div>;
}
function TypeImage(props) {
if (description === 'Residential') {
return <Residential />;
} else
return <Commercial />;
}
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
<TypeImage/>
<div>
</div>
</div>
</div>
</div>
);
}
export default TypeImages;
This isn't working as what is rendered is all 'Image 2' even though there should be some 'Image 1'
Any suggestions on the most efficient way to achieve this?
Thanks!
You can do by many ways,
You need to make sure or check if description has value, if not you probably get unexpected behaviors
Sandbox Example: https://codesandbox.io/s/stupefied-water-sc4o5h?file=/src/App.js
Using ternary conditional statements
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
{/* Doing this */}
{description === "Residential" ? <Residential /> : <Government /> }
<div>
</div>
</div>
</div>
</div>
);
Doing the way that you was working
function TypeImage() {
if (description === 'Residential') {
return <Residential />;
}
return <Government/>;
}
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
<TypeImage/>
<div>
</div>
</div>
</div>
</div>
);
Doing this another way using conditional inline
return (
<div>
<div>
<div className="hidden lg:inline-flex mb-1 px-9">
{description === "Residential" && <Residential /> }
{description === "Government" && <Government/> }
<div>
</div>
</div>
</div>
</div>
);

How Can I change the property of components of React?

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

Cards inside the grid-container: each child in a list should have a unique "key" prop

What I`m doing wrong?It also says: "Check the render method of Card" , which is here:
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={pokemon.id} pokemon={pokemon} />
})}
</div>
Card component itself:
function Card({ pokemon }) {
return (
<div className="card">
<div className="card__image">
<img src={pokemon.sprites.front_default} alt="Pokemon" />
</div>
<div className="card__name">
{pokemon.name}
</div>
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type" style={{backgroundColor: typeColors[type.type.name]}}>
{type.type.name}
</div>
)
})
}
</div>
<div className="card__info">
<div className="card__data card__data--weight">
<p className="title">Weight:</p>
<p>{pokemon.weight}</p>
</div>
<div className="card__data card__data--height">
<p className="title">Height:</p>
<p>{pokemon.height}</p>
</div>
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} Temporary for dev puprose */}
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
)}
</div>
</div>
</div>
);
}
export default Card;
You can use the index of the array may be your data is having some kind of duplicate. It is recommended that you pass a key prop whenever you are returning a list.
<div className="grid-container">
{pokemonData.map((pokemon, i) => {
console.log(pokemon.id) // unique numbers are here
return <Card key={i} pokemon={pokemon} />
})}
</div>
Equally, check this segment of card components.
{
pokemon.types.map((type,i) => {
return (
<div key={i} className="card__type" style={{backgroundColor:
typeColors[type.type.name]}}>
{type.type.name}
/div>
)
})
}
And
<div className="card__data card__data--ability">
<p className="title">Abilities:</p>
{/* {console.log(pokemon.abilities)} }
{pokemon.abilities.map((ability, i) => <p key={i}>{ability.ability.name}
</p>
)}
</div>
Previous answer will solve your problem. However, for your info, I would also like to add here.
For React a key attribute is like an identity of a node/element/tag which helps React to identify each item in the list and apply reconciliation correctlyon each item. Without a key React will render your component but may cause issue when you re-order your list.
React recommends to use id of the data instead of index number. However, if your list does not re-orders/ sorts or do not have id then you can use index.
You can read more here:
https://reactjs.org/docs/lists-and-keys.html
Change this:
<div className="card__types">
{
pokemon.types.map(type => {
return (
<div className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
to:
<div className="card__types">
{
pokemon.types.map((type, key) => {
return (
<div key={key} className="card__type"
style={{backgroundColor:typeColors[type.type.name]}}
>
{type.type.name}
</div>
)
})
}
</div>
and:
{pokemon.abilities.map(ability => <p>{ability.ability.name}</p>
to:
{pokemon.abilities.map((ability,key) => <p key={key} >{ability.ability.name}</p>

Grouping articles based on category on the same page in Gatsby JS

I have a Gatsby JS website and I would like to display on the same page a list of articles grouped by 'families' (categories, basically).
Here's what I did so far:
...
{edges.map(({ node }) => {
let families = []
_.each(edges, edge => {
if (_.get(edge, "node.frontmatter.family")) {
families = families.concat(node.frontmatter.family)
}
})
_.forEach(family => {
const articlesinfamily = () => {
return edges.filter(edge => edge.node.frontmatter.family === family)
}
return (
<>
<div className="column is-3">
<div className="content">
<div className="title is-3">
{family}
</div>
<p>Description</p>
</div>
</div>
<div className="column is-9">
<div className="columns is-multiline">
{articlesinfamily.map(({ node }) => {
<div className="column is-4">
<div className="content">
<div className="title is-4">
{node.frontmatter.name}
</div>
<p>{node.frontmatter.headline}</p>
</div>
</div>
})}
</div>
</div>
</>
)
})
})}
...
This code doesn't work but I think it's the closest I've come to a solution.
The error I get is
Expected an assignment or function call and instead saw an expression
on the line where I have {articlesinfamily.map(({ node }) => {....
Any clue on how to make this work? Is there a better way to achieve the desired result?
Thanks a lot.
This error you had in your initial question:
Expected an assignment or function call and instead saw an expression
...means that this expression inside your map:
{articlesinfamily.map(({ node }) => {
<div className="column is-4">
<div className="content">
<div className="title is-4">
{node.frontmatter.name}
</div>
<p>{node.frontmatter.headline}</p>
</div>
</div>
})}
...is effectively not being used. You are not assigning it to any variables, nor calling a function.
The solution here, as you have found in the answer you posted, is to return the expression (therefore using it in a function):
{articlesinfamily.map(({ node }) => {
return (
<div className="column is-4">
<div className="content">
<div className="title is-4">
{node.frontmatter.name}
</div>
<p>{node.frontmatter.headline}</p>
</div>
</div>
)
})}
You can also use a more concise implicit return by swapping your curly brackets for parentheses:
{articlesinfamily.map(({ node }) => (
<div className="column is-4">
<div className="content">
<div className="title is-4">
{node.frontmatter.name}
</div>
<p>{node.frontmatter.headline}</p>
</div>
</div>
))}
After further research, I solved this using Graphql 'group', like this:
Query page:
export const updatesQuery = graphql`
query {
allMarkdownRemark( filter: { frontmatter: { contentType: { eq: "updates" } } } ) {
group(field: frontmatter___family) {
fieldValue
totalCount
edges {
node {
frontmatter {
name
headline
path
}
}
}
}
}
}
`
And then in the page component I used group.map() first, and then edges.map() to catch all the 'content' inside a group. Like so:
...
{data.allMarkdownRemark.group.map(( { fieldValue, edges } ) => {
return (
<>
<div className="column is-3">
<div className="content">
<div className="title">
{fieldValue}
</div>
</div>
</div>
<div className="column is-1"></div>
<div className="column is-8">
<div className="columns is-multiline">
{edges.map(( { node } ) => {
return (
<div className="column is-4">
<div className="content">
<div className="title">{node.frontmatter.name}</div>
<p>{node.frontmatter.headline}</p>
</div>
</div>
)
})}
</div>
</div>
</>
)
})}
...
Hope this helps you as well.

Cannot Render Nested Maps In ReactJS

I am trying to nest maps to render an array within an object
My Cards Component Render Method (Not Nested, Working):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map(
(route, index) =>
<Card busName={this.state.routeList[index].$.tag} />
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
My Cards Component Render Method (Nesteing, Not Working!!):
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
{
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
}
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}
busTitleToDirectionName(int) returns an array of Strings
My Card Subcomponent's render method:
render() {
// Logging to see if render method is called
console.log("Ran");
return (
<div className="card">
<div className="card-header">
<div className="bus-name">
<p>{this.props.busName}</p>
</div>
</div>
</div>
);
}
How it looks like without nesting when it does work (Not enough reputation to post images so here are the links):
https://i.gyazo.com/66414925d60701a316b9f6325c834c12.png
I also log in the Card subcomponent so that we know that the Card component was ran and it logs that it did get called without nesting
https://i.gyazo.com/fb136e555bb3df7497fe9894273bf4d3.png
When nesting, nothing renders and the Card subcomponent isn't being called as there is no logging of it
https://i.gyazo.com/38df248525863b1cf5077d4064b0a15c.png
https://i.gyazo.com/d6bb4fb413dfc9f683b44c88cce04b8a.png
You can try below code in your nested case. In the nesting of map you have to wrap your nested map within a container. Here I use React.Fragment (<> ) as a container.
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
<>
{
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
<Card busName={busDir} />;
});
}
</>
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
Hope it will help you!!
Thanks, Prahbat Kumar, but I figured out the issue. I had to return the subcomponent from the nested map here is the code:
render() {
return (
<div class="mediator-container">
{this.state.routeList.map((route, index) =>
this.busTitleToDirectionName(this.state.routeList[index].$.tag).map(busDir => {
return <Card busName={busDir} />
})
)}
<span class="loader">
<span class="loader-inner"></span>
</span>
</div>
);
}

Categories

Resources