Передача данных через реквизит, а затем установка в состояние становится неопределенной?

avatar
Brandon
1 июля 2021 в 21:31
1247
2
0

При загрузке страницы я получаю данные о погоде для API, а затем отображаю их на боковой панели, а затем, когда вы нажимаете на город, он показывает погоду в городе более подробно. Итак, в основном я передаю данные от родителя к ребенку с помощью реквизита. Мне нужно заполнить подробный компонент некоторыми начальными данными, поэтому я пытаюсь отправить первый объект в массиве данных дочернему компоненту через реквизиты и установить его в состояние, но когда я пытаюсь отобразить его, он не определен, и я не понятно почему.

На самом деле, кажется, что пару раз он возвращается неопределенным, прежде чем установить его, но когда я пытаюсь отобразить его на странице {weather.data.temp}, я получаю сообщение "Невозможно прочитать свойство "temp" из неопределенного".

data

Родитель:

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(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>
                        <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();
    
        useEffect(() => {
            setWeather(props.data);
        }, [props]);
    
        console.log(weather);
        return (
            <Container>
                <Card>
                    <Card.Header> </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;
Источник
raina77ow
1 июля 2021 в 21:40
0

Эта строка — const weather = JSON.parse(event.target.dataset.value); — кажется мне очень странной. Почему вы используете DOM для хранения данных?

Brandon
1 июля 2021 в 22:27
0

По сути, у меня есть эта карта с несколькими разными городами, и когда я нажимаю на определенный город, я хочу отобразить более подробный раздел погоды в городах. Я использовал data-value, чтобы передать значение этой функции handleClick, но его нужно проанализировать, и по какой-то причине, если я проанализирую его где-нибудь, кроме app.js, это даст мне ошибку перекрестного происхождения. Я отредактировал, чтобы показать другой компонент.

Ответы (2)

avatar
realleyriley
1 июля 2021 в 22:40
0

Выпуск

Вызов setState не приводит к немедленному обновлению переменной состояния. Почему?

Решение

Проверьте, определена ли погода, прежде чем обращаться к ней.

Вариант 1: Используйте weather?.temp

Вариант 2. Используйте оператор if: if (!weather)

avatar
Richard Hpa
1 июля 2021 в 22:00
0

Я думаю, проблема связана с вашим useEffect в компоненте ActiveWeather. Поскольку вы передаете только реквизиты в качестве зависимости вашего useEffect, любое изменение реквизита вызовет его. Таким образом, в вашем примере activeWeather, вероятно, запускает его, и затем вы устанавливаете состояние погоды в значение undefined, потому что на этапе монтирования нет никаких данных для передачи.

Если вы ограничите зависимость только props.data. Тогда этот useEffect будет работать только в том случае, если что-то будет передано через данные. Вы даже можете использовать оператор if, чтобы еще раз проверить наличие данных.

useEffect(() => {
  if(props.data){
    setWeather(props.data);
  }
}, [props.data]);

В родительском компоненте вы также передаете data[0] в качестве реквизита данных. При монтировании данные представляют собой пустой массив, поэтому, если вы скажете data[0], он будет неопределенным. Возможно, оберните рендеринг вашего компонента ActiveWeather в if, чтобы проверить, есть ли какие-либо данные

<Col>
   { data.length > 0 &&  <ActiveWeather activeWeather={activeWeather} data={data[0]} /> } 
</Col>

Brandon
1 июля 2021 в 22:46
0

проблема в том, что мои реквизиты по какой-то причине не определены, даже при этом мои реквизиты все еще не определены.

Richard Hpa
1 июля 2021 в 22:51
0

Только что заметил, что вы также передаете данные [0] в качестве реквизита данных, который в начале будет неопределенным, потому что вы пытаетесь получить первую итерацию пустого массива.