Perform conditional render operations on mapped data - React - javascript

I am mapping data within the returned render, but I am wanting to then perform a conditional on the data that has been mapped... Is it possible to do something like this?
export default function App() {
const prod = [
{'name': '1'},
{'name': '2'},
{'name': '3'}
];
return (
<div className="App">
{prod && (
<div>
{prod.map(p => (
// This is the point I get an error
{p.name === '1' && (
<h1>This is 1</h1>
)}
))}
</div>
)}
</div>
);
}
Currently I am getting an error:
Unexpected token, expected "," (16:14)
14 | <div>
15 | {prod.map(p => (
> 16 | {p.name === '1' && (
| ^

Arrow functions with the format x => () return the content of the brackets.
So you are returning what the compiler thinks is an object, as it's wrapped in curly brackets x => ({ ... }) You need to remove the braces:
prod.map(p => (
p.name === '1' && <h1>This is 1</h1>
)
Or explicitly return the value:
prod.map(p => {
return p.name === '1' && <h1>This is 1</h1>
}

If you want to map the data for any specific index then you can check this.
<div>
{prod.map(p => p.name === '1' && <h1>Conditionally Mapped</h1> || <h1>Normally mapped</h1>}
</div>
// similar to the previous one
<div>
{prod.map(p => {
if(p.name === '1') return <h1>Conditionally Mapped</h1>
else return <h1>Normally mapped</h1>
}
</div>

Related

map in react not displaying data with { } (curly brackets)

So I am trying to return the data from API by map and when I am using ( ) these brackets I am getting the data when I use { } to put if statement, I am getting nothing on my web page but still getting the data in console
const Addtocart = () => {
const data = useSelector((state) => state);
console.log("products", data.productData);
const dispatch = useDispatch();
useEffect(() => {
dispatch(productList());
}, []);
return (
<div id="addtocart-info">
<div className="products">
{data.productData.map((item) => { // here this bracket
if (item.id % 2 === 0 || item.id === 0) {
<div key={item.id} className="product-item">
<img src={item.photo} alt="" />
<div>Name : {item.name} </div>
<div>Color : {item.color} </div>
<button onClick={() => dispatch(addToCart(item))}>
ADD to Cart
</button>
</div>;
console.warn(item.id);
} else {
console.log(item.id);
}
})}
</div>
</div>
);
};
export default Addtocart;
Is there any way to put if statement with () or make this work
You are not getting anything because when u use {} you have to use a return keyword, but when you are using () you don't have to use a return keyword because the whole code inside this is considered as a single piece of code even if it's distributed in multiple lines
so change your code to ,
{data.productData.map((item) => { // here this bracket
if (item.id % 2 === 0 || item.id === 0) {
return (
<div key={item.id} className="product-item">
<img src={item.photo} alt="" />
<div>Name : {item.name} </div>
<div>Color : {item.color} </div>
<button onClick={() => dispatch(addToCart(item))}>
ADD to Cart
</button>
</div>
)
} else {
console.log(item.id);
}
})}
If you use curly brackets you also need to use a return statement. Basically if you don't use curly brackets in an arrow function the statement is returned automatically.
Example:
let x = someArray.map(x => x*2); // returns a new array with the expression applied
let x = someArray.map(x => {return x * 2}) // use the return here

How write my condition when using destructuring when mapping over an Array of objects

I am working with the following array of objects:
var persons: {
label: string;
value: string;
}[]
I iterate over the array like this:
{persons?.map((person) => {
return (
<button
key={person.value}
data-active={value === person.value}
>
{person.label}
</button>
);
})}
Now I use destructuring so I don't have to write person.value etc all the time, so I don't have redundant code:
{persons?.map(({ value, label }) => {
return (
<button
key={value}
// data-active={value === person.value}
>
{label}
</button>
);
})}
But how do I get my boolean now data-active={value === person.value} (since now {value === value} is always true)?
If you want to use destructuring, you need to avoid shadowing your existing value variable. You can use renaming in your destructuring pattern:
{persons?.map(({ value: thisValue, label }) => {
return (
<button
key={thisValue}
data-active={value === thisValue}
>
{label}
</button>
);
})}
...but I'd lean toward renaming your outer value variable instead, perhaps calling it activeValue. Then you don't need the renaming:
const activeValue = /*...*/;
// ...
{persons?.map(({ value, label }) => {
return (
<button
key={value}
data-active={activeValue === value}
>
{label}
</button>
);
})}
Use an alias for value (I've used v), so the destructured value won't shadow the value from the outer scope:
{persons?.map(({ value: v, label }) => {
return (
<button
key={v}
data-active={value === v}
>
{label}
</button>
);
})}

Render components conditionally, based on items of deeply nested array

I have a React component that's receiving a data object returned from an API response.
I'm trying to write a function that accepts a field from that data response, checks an element inside of that field and iterates over it checking each object inside the array for the value of a specific alert.
If a value for a specific alert is found I need to render an Icon for that alert.
The data object looks like this:
location: {
...,
details: {
summary: [
{
type: 'calling',
icon: 'phone'
},
{
type: 'power',
icon: 'electric'
},
{
type: 'water',
icon: 'water-icon'
},
]
}
}
And here's the section where I'm trying to conditionally render the icons (this was my first pass and rudimentary attempt):
<div>
{location.alertDetails && (
<IconBox title={`Alerts`}>
<IconSection>
{location.details.summary.includes(type === calling) &&
<CallIcon />
}
{location.details.summary.includes(type === power) &&
<ElectricIcon />
}
{location.details.summary.includes(type === water) &&
<WaterIcon />
}
</IconSection>
</IconBox>
)}
</div>
You may store within components state the array of fetched types:
const [types, setTypes] = useState(location.details.summary.map(({type}) => type))
With that, you may simply render (or not) your icons conditionally:
<div>
{location.alertDetails && (
<IconBox title={`Alerts`}>
<IconSection>
{types.includes('calling') && <CallIcon />}
{types.includes('power') && <ElectricIcon />}
{types.includes('water') && <WaterIcon />}
</IconSection>
</IconBox>
)}
</div>
Here's the demo (with all of your components rendered as a <div>'s, since I dont have those):
const { render } = ReactDOM,
{ useState } = React
const apiData = {location:{details:{summary:[{type:'calling',icon:'phone'},{type:'power',icon:'electric'},{type:'water',icon:'water-icon'},]}}}
const IconTray = ({data}) => {
const [types, setTypes] = useState(data.location.details.summary.map(({type}) => type))
return (
<div>
{data.location.details && (
<div>
<div>
{types.includes('calling') && <div>I am a CallIcon</div>}
{types.includes('power') && <div>I am an ElectronIcon</div>}
{types.includes('water') && <div>I am a WaterIcon</div>}
</div>
</div>
)}
</div>
)
}
render (
<IconTray data={apiData} />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
You can use a map to easily iterate over these -
<div>
{location.alertDetails && location.details.summary.map(item =>{ item.icon && return (
<IconBox title={`Alerts`}>
<IconSection>
{location.details.summary.includes(type === calling) &&
<CallIcon />
}
{location.details.summary.includes(type === power) &&
<ElectricIcon />
}
{location.details.summary.includes(type === water) &&
<WaterIcon />
}
</IconSection>
</IconBox>
)})}
</div>

React: Rendering a method defined inside arrow function?

Hello friends! I hope you are well.
I've got an arrow function called WorldInfo and its parent component is passing down an object in props that for the sake of this example, I'm just calling object. Now In WorldInfo I also want to parse and list the items in object, so I've created the method serverInfoTabList to take object and shove it through .map. My problem is when compiled, my browser does not recognize serverInfoTabList either when it's defined nor called in WorldInfo's own return function.
Here is the error and the code itself.
Line 7:5: 'serverInfoTabList' is not defined no-undef
Line 34:22: 'serverInfoTabList' is not defined no-undef
const WorldInfo = (props) => {
serverInfoTabList = (object) => {
if (object != undefined){
return object.item.map((item) => {
const time = Math.trunc(item.time/60)
return (
<li key={item._id}>{item.name}
<br/>
Minutes Online: {time}
</li>
);
});
}
}
return (
props.object!= undefined ?
<div className={props.className}>
<h1>{props.world.map}</h1>
{/* <img src={props.object.image}/> */}
<div>
<ul>
{serverInfoTabList(props.object)}
</ul>
</div>
</div>
:
null
);
}
Thanks for your time friendos!
You forgot the const declaration
const serverInfoTabList = (object) => {
/* ... */
}
The other problem is that you're accessing properties which doesn't exist props.world for instance. Also you're mapping through an undefined property props.object.item. I've corrected your sandbox
const WorldInfo = props => {
const serverInfoTabList = object => {
return Object.keys(object).map(key => {
const item = object[key];
const time = Math.trunc(item.time / 60);
return (
<li key={item._id}>
{item.name}
<br />
Minutes Online: {time}
</li>
);
});
};
return props.object ? (
<div className={props.className}>
<h1>{props.world.map}</h1>
{/* <img src={props.object.image}/> */}
<div>
<ul>{serverInfoTabList(props.object)}</ul>
</div>
</div>
) : null;
};
class Todo extends Component {
render() {
const object = { item1: { _id: 1, time: 1 }, Item2: { _id: 2, time: 2 } };
return (
<div>
<WorldInfo object={object} world={{ map: "foo" }} />
</div>
);
}
}

Curly braces inside curly braces in React

I have presentational component in React. And with products.some i am trying to check if any item inside products is checked. And if some item is checked, render parent block for RequestedProduct component. I know that the problem is a second pair of curly braces as React think it's a prop. Is there another way to do this?
const Requested = ({ products, getCurrentTime }) => (
<div className="pepper-pin-body-tab requested-tab">
<div className="pepper-pin-body-tab-title">
Запрошенные
</div>
<div className="pepper-pin-body-tab-indicator" />
{products.some(product => product.checked) ? (
<div className="requested-tab-list-requested">
<div className="requested-tab-list-requested-time">
{getCurrentTime()}
</div>
{products.filter((product, key) => {
if (product.checked) {
return (
<RequestedProduct
key={key}
title={product.title}
/>
);
}
})}
</div>
) : null}
</div>
);
Issue is, filter will not return the custom element/value, it will always return the array element for which you return true from filter body.
Solution is, use only map or combination of filter and map.
Using map:
{
products.map((product, key) => product.checked ?
<RequestedProduct key={key} title={product.title} />
: null
}
Using combination of filter and map:
{
products
.filter(product => product.checked)
.map((product, key) => <RequestedProduct key={key} title={product.title}/>)
}
Check this snippet, you will get a better idea:
const arr = [
{a: 1},
{a: 2},
{a: 3},
{a: 4}
];
const afterFilter = arr.filter((el,i) => {
if(i%2) {
return `Hello world ${i}`;
}
});
// it will print the array items, not the Hello World string
console.log('afterFilter', afterFilter);
I'd recomment splitting the code a bit, which makes it intent a lot clearer. You'll end up with the following (for example), which should not be triggering errors.
The main problem is in the unintended side effects of the filter, whereas you most likely want to use a filter and a map. That makes the intent to another developer much clearer.
const contents = (products, getCurrentTime) => (
const filtered = products.filter(product => product.checked);
<div className="requested-tab-list-requested">
<div className="requested-tab-list-requested-time">
{getCurrentTime()}
</div>
{filtered.map((product, key) => <RequestedProduct key={key} title={product.title}/>)}
</div>
);
const Requested = ({products, getCurrentTime}) => {
const isAnythingChecked = products.some(product => product.checked);
return <div className="pepper-pin-body-tab requested-tab">
<div className="pepper-pin-body-tab-title">
Запрошенные
</div>
<div className="pepper-pin-body-tab-indicator"/>
{isAnythingChecked ? contents(products, getCurrentTime) : null}
</div>
};

Categories

Resources