I have a problem rendering my props data
Here I'm trying to pass props to a component with mapped data from a sample data set
const weatherComponents = weatherData.items.map(weather => {
return(
<div key={weather.forecasts.area}>
<WeatherForecast
name={weather.forecasts.area}
condition={weather.forecasts.forecast}>
</WeatherForecast>
</div>
)})
return(
{weatherComponents} )
This is the component
function WeatherForecast(props) {
return(
<div>
<p>Name: {props.name}</p>
<p>Condition: {props.condition}</p>
</div>
)}
This is the sample data set
{
"area_metadata": [
{
"name": "Yishun",
"label_location": {
"latitude": 1.418,
"longitude": 103.839
}
}
],"items": [
{
"forecasts": [
{
"area": "Yishun"
"forecast" : "cloudy"
}
]}
]}
In my browser, it shows Warning: Each child in a list should have a unique "key" prop. and the data are not rendering, it only appears "Name: " without the area name from the data set. Am I mapping the data in the wrong way? Help TT
You have 2 options ... well, 3.
You need an array in "area_metadata" and "items":
1.1. The fast solution:
const weatherComponents = weatherData.items.map(weather => {
return(
<div key={weather.forecasts[0].area}>
<WeatherForecast
name={weather.forecasts[0].area}
condition={weather.forecasts[0].forecast}>
</WeatherForecast>
</div>
)
})
return({weatherComponents})
1.2 The right solution:
const weatherComponents = weatherData.items.map(weather => {
return weather.forecasts.map( casts => (
<div key={casts.area}>
<WeatherForecast
name={casts.area}
condition={casts.forecast}>
</WeatherForecast>
</div>
))
})
return({weatherComponents})
2. You do not need an array:
{
"area_metadata": [
{
"name": "Yishun",
"label_location": {
"latitude": 1.418,
"longitude": 103.839
}
}
],
"items": [
{
"forecasts": {
"area": "Yishun"
"forecast" : "cloudy"
}
}
]
}
Just replace
const weatherComponents = weatherData.items.map(weather => {
return(
<div key={weather.forecasts.area}>
<WeatherForecast
name={weather.forecasts.area}
condition={weather.forecasts.forecast}>
</WeatherForecast>
</div>
)})
return(
{weatherComponents} )
with
const weatherComponents = weatherData.items.map(weather => {
const {area, forecast} = weather.forecasts[0];
return(
<div key={area}>
<WeatherForecast
name={area}
condition={forecast}>
</WeatherForecast>
</div>
)})
return(
{weatherComponents} )
Related
I am receiving a response from the API, but the data doesn't display on the card. I don't think it has much to do with the data I think it has much to do with the card appearing itself first. Here is how the search file is set up, pretty straight forward. As you see I did set up a container to hold the card as I map through it.
import '../styles/searchPage.css'
import SearchCard from '../components/SearchCard';
const API_URL = 'https://api.openbrewerydb.org/breweries?by_city';
const brewery1 = {
"id": "10-barrel-brewing-co-san-diego",
"name": "Nirmanz Food Boutique",
"brewery_type": "large",
"street": "1501 E St",
"phone": "7739888990 ",
"address": null,
"city": "San Diego",
"state": "California",
"postal_code": "92101-6618",
"country": "United States",
}
function SearchPage() {
const [cards, setCards] = useState([]);
const [searchTerm, setSearchTerm] = useState('');
const searchRestaurants = async (name) => {
const req = await fetch(`${API_URL}&s=${name}`);
const data = await req.json()
console.log(data[0].name)
setCards({data: data.name})
}
useEffect(() => {
searchRestaurants('')
}, [])
return (
<div className='search'>
<h1>Enter a City or Town name</h1>
<div className='search-container'>
<input
type="text"
name="search"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter'){
setCards(searchTerm);
}
}}
placeholder="Search..."
class="search-input"
/>
<button
className='next'
onClick={()=> searchRestaurants(searchTerm)}
>Go</button>
</div>
{
cards?.length > 0
? (
<div className="container">
{cards.map((card) =>(
<SearchCard brewery1={brewery1}/>
))}
</div>
) :
(
<div className="empty">
<h2>Found 0 Breweries</h2>
</div>
)
}
</div>
);
}
export default SearchPage
Here is the my JSX for my search card labeling out what I want to display inside that card.
import '../styles/searchPage.css'
const SearchCard = ({brewery1}) => {
return (
<div className="card">
{/* <img src={brewery1.Poster !== 'N/A' ? brewery1.Poster : 'https://via.placeholder.com/400'} alt={brewery1.name /> */}
<div>
<span>{brewery1.id}</span>
<h3>{brewery1.brewery_type}</h3>
<h2>{brewery1.street}</h2>
<h2>{brewery1.adress}</h2>
<h2>{brewery1.phone}</h2>
<h2>{brewery1.city}</h2>
<h2>{brewery1.state}</h2>
<h2>{brewery1.postal_code}</h2>
<h2>{brewery1.country}</h2>
</div>
</div>
)
}
export default SearchCard;
Change this:
setCards(data);
And this:
<SearchCard brewery1={card}/>
In your searchRestaurant method set the data like this:
const searchRestaurants = async (name) => {
const req = await fetch(`${API_URL}&s=${name}`);
const data = await req.json()
//make sure that data got your restaurants list
setCards(data)
}
and in the render like this:
cards.map(card => <SearchCard brewery1={card}/>)
I am using react-bootstrap-typeahead to search in react.
I am facing issue with filtering nested object.
const products = [
{
id : 1,
name : "abc",
applications:[
{
name:"ink",
fullname:"INKK"
},
{
name:"solvent",
fullname:"ssINKK"
}
]
},
{
id:2,
name:"xyz",
applications:[
{
name:"ink22",
fullname:"INKK"
},
{
name:"solvent22",
fullname:"ssINKK"
}
]
}
]
I want to search by application name . For example if search ink22 then it should return object with id:2
Below is my code.Any help will be useful.Thanks.
import React from "react";
import Typeahead from "react-bootstrap-typeahead/lib/components/Typeahead";
export default function Search(props){
const { products } = props
return (
<Typeahead
id="search-product"
labelKey={option => `${option.name}`}
minLength={1}
filterBy={(option, props) => {
console.log(props)
}}
options={products ? products : []}
placeholder="Search"
renderMenuItemChildren={(option, props) => (
<div className="card-body">
<img src="/images/default.svg" className="float-left mt-2"/>
<div className="message ml-5">
<h5 className="card-title">{`${option.ci.name} ${option.name}`} </h5>
<h6 className="card-subtitle text-muted">{`${option.brand.name} ${option.range}`}</h6>
</div>
</div>
)}
/>
);
};
lodash is a good friend.
const products = [
{
id : 1,
name : "abc",
applications:[
{
name:"ink",
fullname:"INKK"
},
{
name:"solvent",
fullname:"ssINKK"
}
]
},
{
id:2,
name:"xyz",
applications:[
{
name:"ink22",
fullname:"INKK"
},
{
name:"solvent22",
fullname:"ssINKK"
}
]
}];
const match = _.find(products, { applications: [{ name: 'ink22' }]});
console.log(match);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.min.js"></script>
What I am trying to do is fetch the inner data of blog_set. But in my case, I'm getting a null value (usually nothing is output).
Is this the correct way to get the value: {bloglist.blog_set.title} ?
api-data:
[
{
"url": "http://localhost:8000/api/category/brown",
"id": 1,
"title": "brown",
"slug": "brown",
"image": "http://localhost:8000/media/category/bg_1.jpg",
"description": "",
"created_on": "2020-05-08T15:21:02Z",
"status": true,
"blog_set": [
{
"id": 6,
"url": "http://localhost:8000/api/blog_detail/test3",
"title": "test3",
"slug": "test3",
"image": "http://localhost:8000/media/blog/author.jpg",
"description": "test3",
"created_on": "2020-05-13T13:36:45Z",
"status": true,
"category": [
1
]
}
]
}
]
./src/Category.js
export default class App extends Component{
state = {
bloglist: [],
};
componentDidMount() {
this.fetchData();
}
fetchData = async () => {
try {
const response = await fetch("http://localhost:8000/api/category");
const jsonResponse = await response.json();
this.setState({ bloglist: jsonResponse });
} catch (error) {
console.log(error);
}
};
render(){
{
const { bloglist } = this.state;
return(
<div>
{bloglist.map((bloglist) => (
<div>
<h3 class="mb-2">{bloglist.blog_set.title}</h3>
</div>
))}
</div>
);
}
}
}
blog_set is an array so it does not have an attribute/memeber/item called title. You should define at what index you want the data.
bloglist.blog_set[0].title
Or iterate over blog_set too
As bloglist is also an array you need to use one more .map() or as bloglist[0].blog_set[0].title
Example:
{bloglist.map((bloglist) => (
<div>
<h3 class="mb-2">{bloglist.blog_set.map(i=> i.title)}
</h3>
</div>
))}
blogList.map() will iterate the parent Array of objects to get blog_set and blog_set.map() will now iterate the blog_set to get list title
{bloglist.map((bloglist) =>(
<div>
<h3 class="mb-2">{bloglist.blog_set.map((list)=>( list.title)}</h3>
</div>)}
blog_set is an array. In order to iterate it, use map and {title}. In each iteration of your blog_set object, there is a key named title (destructured object).
<div>
{bloglist.map((bloglist) => (
<div>
<h3 class="mb-2">{blog_set.map(({title})=>title))}</h3>
</div>
))}
</div>
I have the bellow alike data, and I would like to render them.
Let's say I would like to display firstName, address, and seatType and flightId for each flight the passenger has.This has to be done for each passenger. How can I achieve that?
Updated
[
{
"id": 1,
"firstName": "Smith",
"lastName": "John",
"address": [
"1 Street",
"YYY",
],
"flights": [
{
"flightId": 1,
"seatType": "oridinary"
},
{
}
]
},
{},
]
Here is my code
render() {
const { data } = this.state;
return (
<div>
{" "}
{Object.keys(data).map((key, index) => (
<p key={index}>
{" "}
{key} {data[key].flights}
{data[key].flights.map(k => (
{data[key].flights[k]}
))}
</p>
))}
</div>
);
}
I'm assuming you're looking for something like this:
return (
<div>
{
passengers.map(passenger => {
if (!passenger.id) { return null } /* + */
return (
<div key={passenger.id}>
<span>{passenger.firstName} {passenger.lastName}</span>
<div>
<span>Passenger's Flights</span>
{
passenger.flights && /* + */
Array.isArray(passenger.flights) && /* + */ passenger.flights.map(flight => {
if (flight.flightId) {
return (
<div key={flight.flightId}>
{flight.seatType}
</div>
)
}
return null
})
}
</div>
</div>
)
})
}
</div>
);
}
Note: remember that you should not use index as a key.
Edit: You need to add a null/undefined check
render() {
const { data } = this.state;
return (
<div>
{data.map((passenger, index) => (
<p key={index}>
{passenger.firstName} {passenger.address.join(' ')}
{passenger.flights.map(flight => (
<p>{flight.seatType} {flight.flightId}</p>
))}
</p>
))}
</div>
);
}
render() {
const { data } = this.state;
return (
<div>
{data.map(({id, firstName, address, flights}) => (
<p key={id}>
<div>{firstName}</div>
<div>{address.join(', ')}</div>
{flights.map(f => (<div key={f.flightId}>{f.flightId}-{f.seatType}</div>))}
</p>
))}
</div>
);
}
Not sure if it compiles but it's something like this. Also, if you have an ID, use it as key.
I've been trying to implement a Regex filter in my React project - it's a search bar which I've got to filter even mixed letters in a word.
eg. If I have "Stark" as word or "Karstark", once I type "stk" the word "Stark" should appear.
I already can search if I type "ark" for "Stark" or "ol" for "Bolton"
This is the Json file
[
{
"id" : 1,
"title": "Stark",
"date": "17-08-2017"
},
{
"id" : 2,
"title": "Lannister",
"date": "17-08-2017"
},
{
"id" : 3,
"title": "Targaryen",
"date": "16-08-2017"
},
{
"id" : 4,
"title": "Karstark",
"date": "16-08-2017"
},
{
"id" : 5,
"title": "Bolton",
"date": "15-08-2017"
},
{
"id" : 6,
"title": "Martell",
"date": "15-08-2017"
}
]
This is the search file
import React, { Component } from 'react';
const data = require('../../data.json');
function searchingFor(term){
return function(x){
return x.title.toLowerCase().includes(term.toLowerCase()) || !term ;
}
}
class Results extends Component {
constructor(props){
super(props);
this.state = {
data: data ,
term : '',
}
this.searchHandler = this.searchHandler.bind(this);
}
searchHandler(event){
this.setState({ term: event.target.value})
}
render () {
const {term, data} = this.state;
return (
<section>
<div className="input-group input-group-lg" >
<input type="text"
className="form-control"
aria-label="Large"
placeholder="Pesquise uma nota"
aria-describedby="inputGroup-sizing-sm"
onChange={this.searchHandler}
value={term}
/>
</div>
<div className="App-maintitle">
<h1>Notas</h1>
</div>
{
data.filter(searchingFor(term)).map((element, index) => {
return (
<div className="App-row" key={index} >
<div className="App-titledata">
{element.title}
</div>
<div className="App-date">
{element.date}
</div>
</div>
)
})
}
</section>
)
}
}
export default Results;
Here's a rough overview of how you would implement a search. Basically we're checking to see whether the item.title includes term and if it does, filter out everything else and map the data.
{
data.filter(item => item.title.toLowerCase().includes(term.toLowerCase()).map((element, index) => {
return (
<div className="App-row" key={index} >
<div className="App-titledata">
{element.title}
</div>
<div className="App-date">
{element.date}
</div>
</div>
)
})
}
Your filtered data:
data.filter(item => {
return term.split("").every(internalItem => {
return item.title.toLowerCase().indexOf(internalItem.toLowerCase()) !== -1
})
})