无法将初始数据设置为 child 组件,因为它在页面加载时未定义
Can not set initial data to child component because it is undefined on page load
我有 5 个城市,它们的天气在页面加载时显示在卡片上,当您单击一个城市时,我希望更多详细信息显示在另一张卡片上,但详细卡片需要从第一个城市开始的初始数据卡,但我似乎无法让它工作。我猜问题是数据在页面加载时未定义,所以我不确定如何显示它?我的猜测是我必须在定义数据时有条件地加载详细卡片,但我不确定如何编写它。
Parent
const fetchCity = async (city) => {
const res = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}`);
return {
description: res.data.weather[0].description,
icon: res.data.weather[0].icon,
temp: res.data.main.temp,
city: res.data.name,
country: res.data.sys.country,
id: res.data.id,
};
};
function App() {
const [data, setData] = useState([]);
const [activeWeather, setActiveWeather] = useState([]);
useEffect(() => {
const fetchCities = async () => {
const citiesData = await Promise.all(["Ottawa", "Toronto", "Vancouver", "California", "London"].map(fetchCity)).catch((err) => {
console.log("error:", err);
});
setData((prevState) => prevState.concat(citiesData));
};
fetchCities();
}, []);
const handleClick = (event) => {
const weather = JSON.parse(event.target.dataset.value);
setActiveWeather(weather);
};
return (
<div className="App">
<Header />
<Container>
<Row>
<Col>
<WeatherPanel data={data} handleClick={handleClick} />
</Col>
<Col>
//Probably where I have conditionally render?
<ActiveWeather activeWeather={activeWeather} data={data[0]} />
</Col>
</Row>
</Container>
</div>
);
}
export default App;
卡片详情
import React, { useEffect, useState } from "react";
import { Container, Card } from "react-bootstrap";
const ActiveWeather = (props) => {
const [weather, setWeather] = useState(props.data);
console.log("props", props);
useEffect(() => {
setWeather(props.activeWeather);
}, [props.activeWeather]);
console.log(weather);
return (
<Container>
<Card>
<Card.Header> {weather?.city}</Card.Header>
{weather?.temp}
</Card>
</Container>
);
};
export default ActiveWeather;
初始卡
const WeatherPanel = (props) => {
return (
<div>
<Container fluid>
<Card style={{ boxShadow: "0 0 10px 2px lightgrey" }}>
<Card.Header> Favorite Location</Card.Header>
<ListGroup variant="flush">
<ListGroup.Item>
{props.data.map((item) => (
<ListGroup.Item key={item.id} data-value={JSON.stringify(item)} onClick={props.handleClick}>
<img src={`http://openweathermap.org/img/wn/${item.icon}@2x.png`} alt="Weather Icon" />
{item.city + ", " + item.country}
</ListGroup.Item>
))}
</ListGroup.Item>
</ListGroup>
</Card>
</Container>
</div>
);
};
export default WeatherPanel;
正如您所说,第一次渲染时的数据是未定义的。您可以像这样有条件地在父级呈现 Detail Component
:
function App() {
const [data, setData] = useState([]);
const [activeWeather, setActiveWeather] = useState([]);
useEffect(() => {
const fetchCities = async () => {
const citiesData = await Promise.all(
['Ottawa', 'Toronto', 'Vancouver', 'California', 'London'].map(
fetchCity
)
).catch(err => {
console.log('error:', err);
});
setData(prevState => prevState.concat(citiesData));
};
fetchCities();
}, []);
const handleClick = event => {
const weather = JSON.parse(event.target.dataset.value);
setActiveWeather(weather);
};
return (
<div className="App">
<Header />
<Container>
<Row>
<Col>
<WeatherPanel data={data} handleClick={handleClick} />
</Col>
<Col>
// Since you want to prevent the undefined to passed to children
// You need conditionally render OR conditionally passed the data
// #1 conditionally render
// check the length of the weather
{activeWeather.length &&
<ActiveWeather activeWeather={activeWeather} data={data[0]} />}
// #2 conditionally pass the data
<ActiveWeather activeWeather={activeWeather || []} data={data[0] || []} />
</Col>
</Row>
</Container>
</div>
);
}
export default App;
在 Detail Card
中,您的代码会像这样更好
import React, { useEffect, useState } from "react";
import { Container, Card } from "react-bootstrap";
const ActiveWeather = (props) => {
return (
<Container>
<Card>
<Card.Header> {props?.weather?.city}</Card.Header>
{props?.weather?.temp}
</Card>
</Container>
);
};
export default ActiveWeather;
我有 5 个城市,它们的天气在页面加载时显示在卡片上,当您单击一个城市时,我希望更多详细信息显示在另一张卡片上,但详细卡片需要从第一个城市开始的初始数据卡,但我似乎无法让它工作。我猜问题是数据在页面加载时未定义,所以我不确定如何显示它?我的猜测是我必须在定义数据时有条件地加载详细卡片,但我不确定如何编写它。
Parent
const fetchCity = async (city) => {
const res = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}`);
return {
description: res.data.weather[0].description,
icon: res.data.weather[0].icon,
temp: res.data.main.temp,
city: res.data.name,
country: res.data.sys.country,
id: res.data.id,
};
};
function App() {
const [data, setData] = useState([]);
const [activeWeather, setActiveWeather] = useState([]);
useEffect(() => {
const fetchCities = async () => {
const citiesData = await Promise.all(["Ottawa", "Toronto", "Vancouver", "California", "London"].map(fetchCity)).catch((err) => {
console.log("error:", err);
});
setData((prevState) => prevState.concat(citiesData));
};
fetchCities();
}, []);
const handleClick = (event) => {
const weather = JSON.parse(event.target.dataset.value);
setActiveWeather(weather);
};
return (
<div className="App">
<Header />
<Container>
<Row>
<Col>
<WeatherPanel data={data} handleClick={handleClick} />
</Col>
<Col>
//Probably where I have conditionally render?
<ActiveWeather activeWeather={activeWeather} data={data[0]} />
</Col>
</Row>
</Container>
</div>
);
}
export default App;
卡片详情
import React, { useEffect, useState } from "react";
import { Container, Card } from "react-bootstrap";
const ActiveWeather = (props) => {
const [weather, setWeather] = useState(props.data);
console.log("props", props);
useEffect(() => {
setWeather(props.activeWeather);
}, [props.activeWeather]);
console.log(weather);
return (
<Container>
<Card>
<Card.Header> {weather?.city}</Card.Header>
{weather?.temp}
</Card>
</Container>
);
};
export default ActiveWeather;
初始卡
const WeatherPanel = (props) => {
return (
<div>
<Container fluid>
<Card style={{ boxShadow: "0 0 10px 2px lightgrey" }}>
<Card.Header> Favorite Location</Card.Header>
<ListGroup variant="flush">
<ListGroup.Item>
{props.data.map((item) => (
<ListGroup.Item key={item.id} data-value={JSON.stringify(item)} onClick={props.handleClick}>
<img src={`http://openweathermap.org/img/wn/${item.icon}@2x.png`} alt="Weather Icon" />
{item.city + ", " + item.country}
</ListGroup.Item>
))}
</ListGroup.Item>
</ListGroup>
</Card>
</Container>
</div>
);
};
export default WeatherPanel;
正如您所说,第一次渲染时的数据是未定义的。您可以像这样有条件地在父级呈现 Detail Component
:
function App() {
const [data, setData] = useState([]);
const [activeWeather, setActiveWeather] = useState([]);
useEffect(() => {
const fetchCities = async () => {
const citiesData = await Promise.all(
['Ottawa', 'Toronto', 'Vancouver', 'California', 'London'].map(
fetchCity
)
).catch(err => {
console.log('error:', err);
});
setData(prevState => prevState.concat(citiesData));
};
fetchCities();
}, []);
const handleClick = event => {
const weather = JSON.parse(event.target.dataset.value);
setActiveWeather(weather);
};
return (
<div className="App">
<Header />
<Container>
<Row>
<Col>
<WeatherPanel data={data} handleClick={handleClick} />
</Col>
<Col>
// Since you want to prevent the undefined to passed to children
// You need conditionally render OR conditionally passed the data
// #1 conditionally render
// check the length of the weather
{activeWeather.length &&
<ActiveWeather activeWeather={activeWeather} data={data[0]} />}
// #2 conditionally pass the data
<ActiveWeather activeWeather={activeWeather || []} data={data[0] || []} />
</Col>
</Row>
</Container>
</div>
);
}
export default App;
在 Detail Card
中,您的代码会像这样更好
import React, { useEffect, useState } from "react";
import { Container, Card } from "react-bootstrap";
const ActiveWeather = (props) => {
return (
<Container>
<Card>
<Card.Header> {props?.weather?.city}</Card.Header>
{props?.weather?.temp}
</Card>
</Container>
);
};
export default ActiveWeather;