This is my Results.js
This is my Thumbnail.js
`import React from "react";
const Thumbnail = ({ result }) => {
return (
<div>
<h1>Thumbnail</h1>
</div>
);
};
export default Thumbnail;`
This is in my index.js
<Results results={results} />
When I want to call Thumbnail in Results.js, why the in Results.js not showing ?
results most likely doesn't have any data. If it did, React would loop through the array and render out a Thumbnail for each item in the array.
To test this, set a simple variable in your file to an array of, let's say, 3 items.
const items = [1,2,3];
Then, use this item to map over the Thumbnail component.
export default function Results() {
...
const items = [1,2,3];
return (
<div>
{items.map(item => (
<Thumbnail result={item} />
)}
</div>
)
You should see then three rendered out Thumbnail components
Related
I'm new to React. I'm trying to add additional functionality of deleting the record from the list by setting the value.
here is my App.js
import React, { useState } from "react";
import data from "./data";
import List from "./List";
function App() {
const [movies, setMovie] = useState(data);
return (
<main>
<section className='container'>
<h3>{movies.length} Movies to Watch</h3>
<List movies={movies} setMovie />
<button onClick={() => setMovie([])}>clear all</button>
</section>
</main>
);
}
export default App;
In List.js, Im trying to delete the record when clicking on Watched button. Can I call setMovie inside the List component? is it a correct way?
List.js
import React from "react";
const List = ({ movies }, setMovie) => {
return (
<>
{movies.map((movie) => {
const { id, name, year, image } = movie;
return (
<article key={id} className='person'>
<img src={image} alt={name} />
<div>
<h4>{name}</h4>
<button
className='btn'
onClick={(id) =>
setMovie(movies.filter((movie) => movie.id !== id))
}
>
watched
</button>
<p>{year}</p>
</div>
</article>
);
})}
</>
);
};
export default List;
You have two mistakes in your code. First:
<List movies={movies} setMovie />
This shorthand assigns a value of true to setMovie. To assign the setMovie function to it, you must instead do:
<List movies={movies} setMovie={setMovie} />
And secondly this:
const List = ({ movies }, setMovie) => {
Should be this:
const List = ({ movies, setMovie }) => {
try:
<List movies={movies} setMovie={setMovie} />
this way the funcition will appear in the List component as a prop.
The way you were doing, it will just appear as true
In my react program i have made a DrinkList.js in which i show the images of drink. but when i start make it clickable using Onclick and passing a function to display its name in console. error start flooding.
import React from "react";
// import index from "./src"
const DrinkList = (props) => {
const handleTextShow = (drinkDetail) => {
console.log(drinkDetail.strGlass);
};
return (
<>
{props.drinks.map((drink, index) => (
<div>
<img src={drink.strDrinkThumb} alt="drink" width="300" height="300">
{/* hello */}
onClick={() => handleTextShow(handleTextShow)}
</img>
{/* <h4> {drink.strInstructions} </h4> */}
{/* <Details /> */}
</div>
))}
</>
);
};
export default DrinkList;
say strGlass is detail strDrinkThumb is photo.
The problem is that , in handleTextShow function, instead of passing name of drink to want to console, you're passing handleTextShow function as argument, to solve it replace handleTextShow argument with drink name,
onClick={() => handleTextShow(drink.name)}
I'm new to react. I want to create a simple react web app that receives data from 2 api, and display the data.
I have three components. App.js receive data from two api, and pass the data to FruitGrid.js using hooks and props. FruitGrid.js map the two data received, and pass to FruitItem.
My problem is in FruitGrid.js. Data is received in FruitGrid.js, I can see by console log or print using html tags. But when I try to send the mapped data to FruitItem.js by changing the h1 tag to <FruitItem></FruitItem>, I can only successfully pass one data, not both of them.
FruitGrid.js
import React from 'react';
import FruitItem from './FruitItem';
const FruitGrid = ({ items, images, isLoading }) => {
return isLoading ? (
<h1>Loading...</h1>
) : (
<section>
{items.map((item) => {
return <FruitItem key={item.id} item={item}></FruitItem>
})}
{images.map(image => {
return <FruitItem key={image.id} image={image}></FruitItem>
// return <h1>{image}</h1>
})}
</section>
)
}
export default FruitGrid;
If I only do return <FruitItem key={item.id} item={item}></FruitItem> the item data will show in the correct layout, image won't show since I didn't pass. But if I try to pass both item and image using <FruitItem></FruitItem>. It will show error saying "TypeError: Cannot read property 'name' of undefined" in FruitItem.
FruitItem.js
import React from 'react'
const FruitItem = ({ item, image }) => {
return (
<div className='card'>
<div className='card-inner'>
<div className='card-front'>
<img src={image} alt='' />
</div>
<div className='card-back'>
<h1>{item.name}</h1>
<ul>
</ul>
</div>
</div>
</div>
)
}
export default FruitItem
Can someone help and let me know how i can fix it?
Hey #yywhocodes this is happening because the FruitItem.js is always expecting an item object and your code for the images mapping is not providing the item object -> return <FruitItem key={image.id} image={image}></FruitItem>
What you can do is change the FruitItem.js
from
<h1>{item.name}</h1>
to
{ item ? <h1>{item.name}</h1> : null }
like that it will try to render the item.name only if the item exists.
You are iterating over the two data sources separately, so items are not defined in your images.map and images are not defined in your items.map
In order to combine, assuming the order of the data is the same/the keys are the same in both cases, you could do something like this:
{items.map((item, key) => {
return <FruitItem key={item.id} item={item} image={images[key]}></FruitItem>
})}
You need to pass props key={item.id} item={item} to the child FruitItem component. If you can't pass any props to the FruitItem component, react won't figure out the item.name. Which will be a TypeError.
It's because your FruitItem always expects an item to be handed in
<h1>{item.name}</h1>
But when you hand in your image, there is no item you set.
I have a list of items and for each item in the list has an edit button to show a modal with that items details. Originally I had a single modal component in the parent and when I click the edit button it would pass the visible values up to the parent state to show the modal.
The problem is when I did that, the entire list would re render which I dont want because the list can have hundreds of items in it. So right now the solution I have is that in each item of the list I have a modal associated with it. It works but it doesnt seem right because I am duplicated code unnecessarily.
The code is too large to put on here but these are the relevant parts:
import Modal from '../Modal';
const CustomCard = ({
...omitted
}) => {
const [editCustomerModal, setEditCustomerModal] = useState(false);
const onEditModal = () => {
setEditCustomerModal(true);
};
return (
<>
<CustomerModal
onSuccess={handleUpdateCustomer}
onCancel={handleCancelModal}
visible={editCustomerModal}
title="Edit Customer"
details={{
.. ommitted
}}
/>
<Card />
....data
</Card>
</>
);
};
export default CustomCard;
import CustomCard from '../CustomerCard/index';
const CustomList = ({ dataSource }) => {
return (
<div>
{dataSource?.map(i => (
<CustomCard
...props ommitted
/>
))}
</div>
);
};
export default CustomerList;
import CustomerList from './components/CustomerList/index';
// import Modal from './components/AddCustomerModal';
const CustomersPage = () => {
const [editCustomerModal, setEditCustomerModal] = useState(false);
const [editCustomer, setEditCustomer] = useState(null);
return (
<>
// This is where I would want it ideally
<Modal
onSuccess={handleSaveCustomerEdit}
onCancel={handleCancelCustomerEdit}
visible={editCustomerModal}
details={editCustomer}
/>
<CustomerList
dataSource={data}
/>
</div>
{/* </ModalContext.Provider> */}
</>
);
};
export default CustomersPage;
You can define one selected useState atribute, that stores only the register that you want to pass to your modal.
For example:
import CustomerList from './components/CustomerList/index';
import Modal from './components/AddCustomerModal';
const CustomersPage = () => {
const [editCustomerModal, setEditCustomerModal] = useState(false);
const [editCustomer, setEditCustomer] = useState(null);
const [selected, setSelected] = useState(null);
return (
<>
<Modal
onSuccess={handleSaveCustomerEdit}
onCancel={handleCancelCustomerEdit}
visible={editCustomerModal}
details={editCustomer}
selectedCard={selected}
/>
{dataSource?.map(i => (
<CustomCard ...props ommitted setSelected={setSelected}/>
//somewere in CustomCard, trigger the event to set selected props that you want to pass for Modal
//remember to be careful with nullable object. use selectedCard?.something
))}
</>
);
};
export default CustomersPage;
Let's say I have an app which looks like this:
<>
<Component />
<button>Add New Component</button>
</>
How can I make it so every time the button is clicked, a new <Component /> is being appended? It's not about conditional rendering when we show a component or hide it, It's about a possibility to add unlimited amount of new components. Do you have any ideas?
The general workflow is that you store component data (or just identifiers) in an array in state. You then map over the array to render your Component list. The button adds a new identifier/data set to the array.
const App = () => {
const [list, setList] = useState([0]);
const addComponent = () => {
setList([...list, list.length]);
};
return (
<>
{list.map(id => <Component key={id} />)}
<button onClick={addComponent}>Add New Component</button>
</>
)
};
This is a very simple example. In reality you would want to assign unique ids for the keys and probably package it with some more data as an object, but you get the idea.