Use ternary operator to show specific items from state - javascript

I'm unable to show conditional output with the ternary operator. I want to pass a value to a function and show only related info from the state. My code:
import React, {useState} from 'react';
function Tasks({taskId, index}){
{task.parentId == taskId : } //Unable to code this.
return( //show only tasks where parentId == taskId
<div>
<div> {task.title} </div>
<div> {task.body} </div>
</div>
)
}
function App(){
const[tasks, setTasks] = useState([
{
taskId: 1,
title: 'Task1',
body: 'This is the body of the task1',
isComplete: false,
parentId: 0
},
{
taskId: 2,
title: 'Task2',
body: 'This is the body of the task2',
isComplete: false,
parentId: 1
},
{
taskId: 3,
title: 'Task3',
body: 'This is the body of the task3',
isComplete: false,
parentId: 1
},
{
taskId: 4,
title: 'Task4',
body: 'This is the body of the task4',
isComplete: false,
parentId: 3
}
])
return(
<div style={{marginLeft: 20}}>
<h1>ToDo</h1>
{tasks.map((task, index)=>
<Tasks
taskId=1
/>
)}
</div>
)
}
export default App;
So, I want to only show the tasks that have the parentId as 1. How should I go about this?

If you're trying to render only those tasks with the specified id, you may not have to use the ternary operator.
function renderTasks(id) {
return tasks
.filter(({ taskId }) => taskId == id)
.map(({ title, body }) => (
<div>
<div> {title} </div>
<div> {body} </div>
</div>
));
}

For the least modification to the code, you can return an empty fragment or null:
function Tasks({ task }) {
return task.parentId == task.taskId
? (
<div>
<div> {task.title} </div>
<div> {task.body} </div>
</div>
)
: null;
}
(make sure to use parentId, not pasrentId, and task.taskId, not taskId - you aren't passing task as a prop currently, so change the code to do so: <Tasks task={task} />)
But I think it'd make more sense to use .filter in the caller:
return (
<div style={{ marginLeft: 20 }}>
<h1>ToDo</h1>
{tasks
.filter(task => task.parentId === task.taskId)
.map(task => <Task task={task} />)
}
</div>
)
(since Tasks renders a single task, consider calling it Task instead of Tasks)

Related

How to send a property from an array of object from a child component to the parent component?

I have App, that is the parent component and I have the Child component:
The Child component gets a props called items so it can be reused depending on the data. It the example there is data, data1 and data2.
The thing is that I want to set a cookie from the parent component, to set the cookie I need the property link from data2, but I am already mapping data2 in the Child component.
What can I do to obtain the value of the property link in the parent component to pass it as an arguement here:
<Child
onClick={() =>
handleUpdate('How can I obtain here the string from link of data2?')
}
items={data2}
/>
This is the whole example code:
import * as React from 'react';
import './style.css';
const data = [
{ title: 'hey', description: 'description' },
{ title: 'hey1', description: 'description' },
{ title: 'hey2', description: 'description' },
];
const data1 = [
{ title: 'hey', description: 'description' },
{ title: 'hey1', description: 'description' },
{ title: 'hey2', description: 'description' },
];
const data2 = [
{ title: 'hey', link: 'link/hey' },
{ title: 'hey1', link: 'link/he1' },
{ title: 'hey2', link: 'link/he2' },
];
export default function App() {
const [, setCookie] = useCookie('example');
const handleUpdate = (cookie) => {
setCookie(null);
setCookie(cookie);
};
return (
<div>
<h2>App - Parent</h2>
<Child items={data} />
<Child items={data1} />
<Child
onClick={() =>
handleUpdate('How can I obtain here the string from link of data2?')
}
items={data2}
/>
</div>
);
}
export function Child({ items }) {
return (
<div>
<h2>Child</h2>
<ul>
{items.map((item) => {
return (
<>
<p>{item.title}</p>
<a href={item.link}>Go to title</a>
</>
);
})}
</ul>
</div>
);
}
Thank you!
If you want to get the link from the Child component you can simply add a link parameter in the callback:
<Child
onClick={(link) => handleUpdate(link)}
items={data2}
/>
Then from the Child you just need to call the onClick prop:
export function Child({ items, onClick }) { // here make sure to add the prop while destructuring
<a href={item.link} onClick={() => onClick(item.link)}>Go to title</a>
The map method doesn't change the array that it is called on, it just returns a new array, do the items array doesn't get affected at all here, so you can just call it normally like so:
return (
<div>
<h2>App - Parent</h2>
<Child items={data} />
<Child items={data1} />
<Child
onClick={() =>
handleUpdate(data2[0].link)
}
items={data2}
/>
</div>
);
Also, your Child component needs to accept the onClick function as a prop like so:
export function Child({ items, handleClick }) {
return (
<div onClick={handleClick}>
<h2>Child</h2>
<ul>
{items.map((item) => {
return (
<>
<p>{item.title}</p>
<a href={item.link}>Go to title</a>
</>
);
})}
</ul>
</div>
);
}

map function not showing elements on screen

i have this part of code the map function did not show any element of the array, if i console.log the variable it shows me the elements but for some reasons i can't show the elements on the screen.
Code
function Solution({list}){
const data = list
console.log(data);
return(
<div>
{
data?.map((item) => {
return (
<div>
<p> {item.title} </p>
</div>
)
})
}
</div>
)
}
export default Solution;
const list = [
{
title: "Home"
},
{
title: "Service",
subItem: ["Clean", "Cook"]
},
{
title: "Kitchen",
subItem: ["Wash", "Dish"]
},
];
Solution({list})
Please, just pass "list" link this.
<Solution list={list}/>
Hope will help you, Thanks)
Check this out
import React from 'react';
function Solution({list}){
const data = list
console.log(list);
return(
<div>
{
data?.map((item) => {
return (
<div key={item.id}>
<p> {item.title} </p>
</div>
)
})
}
</div>
)
}
export function App(props) {
const list = [
{
id:1,
title: "Home"
},
{
id:2,
title: "Service",
subItem: ["Clean", "Cook"]
},
{
id:3,
title: "Kitchen",
subItem: ["Wash", "Dish"]
},
];
return (
<div className='App'>
<Solution list={list} />
</div>
);
}
// Log to console
console.log('Hello console')
Have a unique key prop for each element when you map an array and send list array as props to your Solution component

How to get the "x" element in React JS while using the map object

I have an array with objects I am using map to render the elements on the page, The problem is that I want to get the last object from the array (in my case it is 'documents') and set a class for it to style it, you can also see my code in codesandbox
export default function Nav() {
const [navItems] = useState([
{
id: 1,
name: "Home",
link: "/dashboard"
},
{
id: 2,
name: "Investments",
link: "/investments"
},
{
id: 3,
name: "Organize",
link: "/organize"
},
{
id: 4,
name: "Documents",
link: "/documents"
}
]);
return (
<div className="App">
{navItems.map((i) => {
return (
<div key={i.id}>
<p>{i.name}</p>
</div>
);
})}
</div>
);
}
Check the index of the item while mapping through it. And check if the index is equal to the navItems.length - 1. Check this-
<div className="App">
{navItems.map((item, index) => {
return (
<div
key={item.id}
className={index === navItems.length - 1 ? 'your-desired-class': ''}>
<p>{item.name}</p>
</div>
);
})}
</div>

State is undefined

I'am trying to fetch data from an API, then set it on my State and display that state in a table. The issue is that the render method is called first and causes my state to be undefined which causes this issue:
The console.log()
https://i.gyazo.com/642f8d6fe3481d2db9763091618e19de.png
state = {
loading: true,
data: [],
customColumns: [],
}
componentDidMount = () => {
axios.get('http://localhost:8080/lagbevakning/revision/subscriptions?id=' + (this.props.match.params.id)).then(response => {
this.setState({
data: response.data,
loading: false
})
})
axios.get('http://localhost:8080/lagbevakning/company?id=' + sessionStorage.getItem("id")).then(response2 => {
this.setState({
customColumns: response2.data
})
})
}
displayCustomColumn = (columnInput) => {
if(columnInput === null) {
return
} else {
return <Table.HeaderCell>{columnInput}</Table.HeaderCell>
}
}
displayList = () => {
return (
<div>
<Table celled>
<Table.Header>
<Table.Row>
{this.displayCustomColumn(this.state.customColumns.customHeaderName1)}
{this.displayCustomColumn(this.state.customColumns.customHeaderName2)}
</Table.Row>
</Table.Header>
{this.state.data.map((item, i) => (
<Table.Body key={i}>
<Table.Row>
<Table.Cell>{item}</Table.Cell>
<Table.Cell>{item}</Table.Cell>
</Table.Row>
</Table.Body>
))}
</Table>
</div>
)}
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
)
}
}
Any suggestions on how to solve this issue is much appreciated, thank you.
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
)
}
I think you are expecting data to be array so you can't access name and id from data state. Check structure of your response and set it accordingly.
Can you try adding the following :
render() {
return (
<div>
{this.state.loading
? <div><h1>LOADING...</h1></div>
:
<h2> Company Name: {this.state.customColumns.companyName} <br/>
Revision Name: {this.state.data.name} <br/>
Revision ID: {this.state.data.id} </h2>
}
{this.state.data.length > 0 && this.displayList()}
</div>
)
}
You can probably try this.
render() {
if (this.state.loading) return <div><h1>LOADING...</h1></div>;
return (
<div>
{this.state.data && this.state.data.length &&
<div>
<h2> Company Name: {this.state.customColumns.companyName} <br />
Revision Name: {this.state.data.name} <br />
Revision ID: {this.state.data.id} </h2>
}
{this.displayList()}
</div>
</div>
)
}
}
You can return immediately if loading is true.
Below that you can check for data which is array of objects.

How to render an array of objects in React?

could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night ยท Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}

Categories

Resources