ReactJs does not render when I use props - javascript

There seems to be a problem with the function Card(props).
The output is fine if I replace the function's content with
<img src="data[0].img" instead of props.img, etc.
var data =
[{
id: 1,
name: "tokyo",
descr: "a",
img: "/tokyo.png"
}
]
function Card(props) {
return (
<div>
<img src={props.img}/>
<h1> {props.name}</h1>
<p> {props.descr}</p>
</div>
)
}
const cards = data.map(item => {
return (<Card
img={item.img}
name={item.name}
descr={item.descr}
key={item.id} />)
})
ReactDOM.render({cards},document.getElementById("root"))

Related

Toggle button value based on state values in React.js

I'm displaying different cars and a button to add or remove the selections the user has made. How do I get the buttons to change state individually? As of now, it changes the state of all the buttons to one value.
const cars = [
{ name: "Benz", selected: false },
{ name: "Jeep", selected: false },
{ name: "BMW", selected: false }
];
export default function App() {
const isJeepSelected = true;
const isBenzSelected = true;
return (
<div className="App">
{cars.map((values, index) => (
<div key={index}>
<Item
isBenzSelected={isBenzSelected}
isJeepSelected={isJeepSelected}
{...values}
/>
</div>
))}
</div>
);
}
const Item = ({ name, isBenzSelected, isJeepSelected }) => {
const [toggle, setToggle] = useState(false);
const handleChange = () => {
setToggle(!toggle);
};
if (isBenzSelected) {
cars.find((val) => val.name === "Benz").selected = true;
}
console.log("cars --> ", cars);
console.log("isBenzSelected ", isBenzSelected);
console.log("isJeepSelected ", isJeepSelected);
return (
<>
<span>{name}</span>
<span>
<button onClick={handleChange}>
{!toggle && !isBenzSelected ? "Add" : "Remove"}
</button>
</span>
</>
);
};
I created a working example using Code Sandbox. Could anyone please help?
There's too much hardcoding here. What if you had 300 cars? You'd have to write 300 boolean useState hook calls, and it still wouldn't be dynamic if you had an arbitrary API payload (the usual case).
Try to think about how to generalize your logic rather than hardcoding values like "Benz" and Jeep. Those concepts are too closely-tied to the arbitrary data contents.
cars seems like it should be state since you're mutating it from React.
Here's an alternate approach:
const App = () => {
const [cars, setCars] = React.useState([
{name: "Benz", selected: false},
{name: "Jeep", selected: false},
{name: "BMW", selected: false},
]);
const handleSelect = i => {
setCars(prevCars => prevCars.map((e, j) =>
({...e, selected: i === j ? !e.selected : e.selected})
));
};
return (
<div className="App">
{cars.map((e, i) => (
<div key={e.name}>
<Item {...e} handleSelect={() => handleSelect(i)} />
</div>
))}
</div>
);
};
const Item = ({name, selected, handleSelect}) => (
<React.Fragment>
<span>{name}</span>
<span>
<button onClick={handleSelect}>
{selected ? "Remove" : "Add"}
</button>
</span>
</React.Fragment>
);
ReactDOM.createRoot(document.querySelector("#app"))
.render(<App />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="app"></div>
Consider generating unique ids for elements rather than using indices or assuming the name is unique. crypto.randomUUID() is a handy way to do this.

React JS Mapping Array and Unpacking Specific Values

I am trying to map over specific values in an array of objects.
I have collected data from my Backend API and this is the response:
// An array of objects
console.log(response.data) =
[
{name:"Bryan",age:"25",sport:"basketball"},
{name:"Justin",age:"30",sport:"soccer"},
{name:"Mark",age:"28",sport:"basketball"},
{name:"Cowell",age:"27",sport:"soccer"},
]
I put this data into a state ("data") using "useState()" from React and used a useEffect to unpack the data upon rendering.
const [data, setData] = useState([])
// some function to store response.data in state
setData(response.data)
I want to map these values onto my Browser in the following way such that Soccer players are displayed in the first div and Basketball players in the second div:
(tried several ways but they resulted in parsing errors)
function App() {
const [data, showData] = useState([])
return (
<div>
{data.map(info => {
<div>
<h1> Sport: soccer </h1>
<h5> {info.name} </h5>
</div>
<div>
<h1> Sport: basketball</h1>
<h5> {info.name} </h5>
</div>
}
)}
</div>
)
}
I am trying to group the names within the same div block (same sport) and not 2 different div blocks for each sport.
You need to return the elements from the map function and also remove the part where you hardcode basketball.
{data.map((info, idx) => (
<div key={idx}>
<h1> Sport: {info.sport} </h1>
<h5> {info.name} </h5>
</div>
))}
const groupBy = (array, getGroupByKey) => {
return (
(array &&
array.reduce((grouped, obj) => {
const groupByKey = getGroupByKey(obj);
if (!grouped[groupByKey]) {
grouped[groupByKey] = [];
}
grouped[groupByKey].push(obj);
return grouped;
}, {})) ||
{}
);
};
const App = (props) => {
var [data, setData] = React.useState([
{ name: 'Bryan', age: '25', sport: 'basketball' },
{ name: 'Justin', age: '30', sport: 'soccer' },
{ name: 'Mark', age: '28', sport: 'basketball' },
{ name: 'Cowell', age: '27', sport: 'soccer' },
]);
const players = groupBy(data, (player) => player.sport);
const sportKeys = Object.keys(players);
return (
<div>
{sportKeys.map((info, idx) => (
<div key={idx}>
<h1> Sport: {info} </h1>
{players[info].map((player, i) => (
<h5 key={i}>{player.name}</h5>
))}
</div>
))}
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

How do I write a delete handler function with React Hooks?

I am creating a flashcard app in React using hooks and having trouble deleting a deck of flashcards. I am able to render Bootstrap cards on the page with the flashcards name, description, card count, and the buttons as desired. However, I am unable to delete a deck of cards as I'm being told setFlashcards is not a function. Here is my code:
App.js
function Layout() {
const [flashcards, setFlashcards] = useState([])
useEffect(() => {
axios
.get('http://localhost:5000/decks?_embed=cards')
.then(res => {
setFlashcards(res.data.map((questionItem, index) => {
return {
id: `${index}-${Date.now()}`,
name: questionItem.name,
description: questionItem.description,
cards: questionItem.cards.length,
}
}))
})
}, [])
return (
<div>
<Header />
<ShowAllDecks flashcards={flashcards} setFlashcards={setFlashcards} />
<NotFound />
</div>
)
}
ShowAllDecks.js
function ShowAllDecks({ flashcards, setFlashcards }) {
return (
<div className='container'>
<button>Create New</button>
{flashcards.map((flashcard) => {
return <Deck flashcards={flashcards} flashcard={flashcard} key={flashcard.id} />
})}
</div>
)
}
Deck.js
function Deck({ flashcard, flashcards, setFlashcards }) {
const deleteHandler = () => {
setFlashcards(flashcards.filter(el => el.id !== flashcard.id))
}
return (
<div className='container'>
<div className='card'>
<div className='card-body'>
<h3 className='card-title'>{flashcard.name}</h3>
<p className='card-text'>{flashcard.description}</p>
<p className='card-text'>{flashcard.cards} cards</p>
<button>View</button>
<button>Study</button>
<button onClick={deleteHandler}>Delete</button>
</div>
</div>
</div>
)
}
Example of a deck with one card:
[
{
'id': 1,
'name': 'A Deck Name'
'description': 'A Deck Description',
'cards': [
{
'id': 1,
'front': 'Front of card',
'back': 'Back of card',
'deckId': 1
}
]
}
]
I'm assuming you're running call to get the flashcards in App.js because you're going to want to pass it to other components? Might be best to use Context too if you're going to drill the props down to other components a lot. Otherwise if it's only going to be for showing All decks then you can run the fetch inside the AllDecks component. Anyway I've changed your code below keeping it in App.js:
App.js
function Layout() {
const [flashcards, setFlashcards] = useState([])
const deleteHandler = (id) => {
setFlashcards(flashcards.filter(deck => deck.id !== id));
}
useEffect(() => {
axios
.get('http://localhost:5000/decks?_embed=cards')
.then(res => {
setFlashcards(res.data.map((questionItem, index) => {
return {
id: `${index}-${Date.now()}`,
name: questionItem.name,
description: questionItem.description,
cards: questionItem.cards.length,
}
}))
})
}, [])
return (
<div>
<Header />
<ShowAllDecks flashcards={flashcards} deleteHandler={deleteHandler} />
<NotFound />
</div>
)
}
ShowAllDecks.js
function ShowAllDecks({ flashcards, deleteHandler }) {
return (
<div className='container'>
<button>Create New</button>
{flashcards.map((flashcard) => {
return <Deck flashcard={flashcard} key={flashcard.id} deleteHandler={deleteHandler} />
})}
</div>
)
}
Deck.js
function Deck({ flashcard, deleteHandler }) {
return (
<div className='container'>
<div className='card'>
<div className='card-body'>
<h3 className='card-title'>{flashcard.name}</h3>
<p className='card-text'>{flashcard.description}</p>
<p className='card-text'>{flashcard.cards} cards</p>
<button>View</button>
<button>Study</button>
{/*
** this will now run the deleteHandler in the App component and pass
** the id of the current deck to it. It will then run the state hook
** and set the new flashcards without this deck
*/}
<button onClick={() => deleteHandler(flashcard.id)}>Delete</button>
</div>
</div>
</div>
)
}

Why is map() only displaying the last object in the array?

I am currently learning React and I am trying to render my JSON data to the page. I used the map(), however it is only rendering the last object from the array onto the page.
class ContentCard extends Component {
state = {
products: ProductInfo
};
render() {
console.log(this.state.products);
return (
<>
{this.state.products.map(items => (
<div className="container page-wrapper">
<div className="page-inner">
<div className="row">
<div className="el-wrapper">
<div className="box-up">
<img className="img" src={items.img} alt="" />
<div className="img-info">
<div className="info-inner">
<span className="p-name">{items.name}</span>
<span className="p-company">{items.company}</span>
<span className="price">
{items.price.toLocaleString("en-US", {
style: "currency",
currency: "USD"
})}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
))}
</>
);
}
}
Here is my Json Data. The image links would have been too long so i just added a sample image to make it easier to read.
const products = [
{
id: 1000,
company: "YEEZY",
categoryName: "Men",
category: "tShirt",
name: "I feel like Pablo",
img: "http://code.slicecrowd.com/labs/4/images/t-shirt.png",
price: 120.0
},
{
id: 1000,
company: "H&M",
categoryName: "Men",
category: "tShirt",
name: "butterfly",
img: "http://code.slicecrowd.com/labs/4/images/t-shirt.png",
price: 120.0
},
{
id: 1000,
company: "North Face",
categoryName: "Men",
category: "Jacket",
name: "WindBreaker",
img: "http://code.slicecrowd.com/labs/4/images/t-shirt.png",
price: 120.0
}
];
export default products;
You need to add a key when you render multiple items in an array.
array.map(item => (
<div key={item.unique_property}>
[...]
</div>
))
Also, are you definitely on React 16.2 + ? I.e. do you have the necessary Fragment syntax support?
This example could help you:
import React, { useState, useEffect } from 'react';
const MyPost = () => {
const [post, setPost] = useState([]);
useEffect(() => {
fetch('url')
.then(res => res.json())
.then(jsonData => setPost([...jsonData]));
}, []);
return (
<>
{post.length > 0 ? (
<ol>
{post.map(p => (
<li key={p.replace(/' '/g, '')}>{p}</li>
))}
</ol>
) : (
<h1>No post Available</h1>
)}
</>
);
};
export default MyPost;

Passing a JS object as a React props

I am taking a React course and we are asked to pass a single JavaScript object as props to a React app. Below is my code:
import React from 'react';
import ReactDOM from 'react-dom';
const App = ( ) => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
const Header = ( ) => {
return (
<div>
<h1>{course.name}</h1>
</div>
)
}
const Content = ( ) => {
return (
<div>
<Part name={course.parts} exercises={course.parts} />
<Part name={course.parts} exercises={course.parts} />
<Part name={course.parts} exercises={course.parts} />
</div>
)
}
const Part = ( ) => {
return (
<div>
<p>{course.parts} {course.parts}</p>
</div>
)
}
const Total = () => {
return (
<div>
<p>Number of exercises {course.parts + course.parts + course.parts}</p>
</div>
)
}
return (
<div>
<Header course={{course}} />
<Content course={course} />
<Total course={course} />
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
It is returning an error --> Objects are not valid as a React child.
I couldn't use this with the arrow function. I tried props but couldn't fix it. Please can someone help me to refactor and fix my code.
Here is a code that should work as desired: Code. Your course.parts is an array and that is one of the reasons why some errors occured. However, there were some more problems related to props and I would suggest reading React documentation.
You can also avoid hard-coded values in Content component by using map() function:
const Content = () => {
return (
<div>
{course.parts.map(singlePart => {
return <Part singlePart={singlePart} />;
})}
</div>
);
};
Many useful array functions are described here.
Try to use Props this way:
const App = ( ) => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
const Header = ({course}) => {
return (
<div>
<h1>{course.name}</h1>
</div>
)
}
const Content = ({course}) => {
//use parts.map(el => <Part part={el}) instead
return (
<div>
<Part part={course.parts[0]} />
<Part part={course.parts[1]}/>
</div>
)
}
const Part = ({part}) => {
return (
<div>
<p>{part.name} {part.exercises}</p>
</div>
)
}
const Total = ({course}) => {
// dont forget to refactor counting exercises with reduce function or something prettier
return (
<div>
<p>Number of exercises {course.parts[0].exercises + course.parts[1].exercises + course.parts[2].exercises}</p>
</div>
)
}
return (
<div>
<Header course={course} />
<Content course={course} />
<Total course={course} />
</div>
)
}
Also, you could have problem with
<Header course={{course}} />
because you pass Object {course: {name: '...', parts: [...]}} as props, not {name: '..', parts: [..]}
Finally, you can move out your Header, Content, Total components from App component.

Categories

Resources