#javascript #reactjs #react-lifecycle
#javascript #reactjs #react-жизненный цикл
Вопрос:
Ну, я создаю это приложение погоды с использованием api. Итак, сначала я должен показать погоду города по умолчанию. Затем, когда я выберу другие города, компонент снова выполнит рендеринг, чтобы предоставить мне данные о погоде в выбранных городах. До сих пор я делал в своем проекте:
const initialDivisionId = "3";
const getDivision = (divisionId) => {
return divisions.find((division) => division.id === divisionId);
};
class Weather extends React.Component {
constructor(props) {
super(props);
const division = getDivision(initialDivisionId);
this.state = {
divisionId: initialDivisionId,
lat: division.lat,
long: division.long,
currentWeatherData: [],
hourlyWeatherData: [],
dailyWeatherData: []
};
}
onDivisionChange = (event) => {
const divisionId = event.target.value;
const { lat, long } = getDivision(divisionId);
this.setState({
divisionId: event.target.value,
lat: lat.lat,
long: long.long
});
};
componentDidMount() {
fetch(
`https://api.openweathermap.org/data/2.5/onecall?lat=${this.state.lat}amp;lon=${this.state.long}amp;units=metricamp;exclude=alertsamp;appid={api_key}`
)
.then((res) => res.json())
.then(
(result) => {
this.setState({
currentWeatherData: result.current,
hourlyWeatherData: result.hourly[0],
dailyWeatherData: result.daily[0]
});
},
(error) => {
console.log(error);
this.setState({
error
});
}
);
}
render() {
console.log(this.state.currentWeatherData);
console.log(this.state.hourlyWeatherData);
console.log(this.state.dailyWeatherData);
return (
<div>
<Title />
<Select
variant="filled"
w="30%"
placeholder="Select option"
value={this.state.divisionId}
onChange={this.onDivisionChange}
>
{divisions.map((division) => (
<option key={division.id} value={division.id}>
{division.name}
</option>
))}
</Select>
<div>
<Stack spacing={6}>
<Heading color="tomato" size="4xl">
{this.state.currentWeatherData.dt}
</Heading>
<Heading color="gray" size="3xl">
{this.state.currentWeatherData.temp}
</Heading>
<Heading color="blue" size="2xl">
{this.state.hourlyWeatherData.pressure}
</Heading>
<Heading color="black" size="xl">
{this.state.hourlyWeatherData.temp}
</Heading>
<Heading color="black" size="lg">
{this.state.dailyWeatherData.clouds}
</Heading>
<Heading color="yellow" size="md">
{this.state.dailyWeatherData.humidity}
</Heading>
</Stack>
</div>
</div>
);
}
}
const Title = () => {
return (
<Text align="center">
<Heading size="xl">Weather App</Heading>
</Text>
);
};
function App() {
return (
<ChakraProvider>
<Weather />
</ChakraProvider>
);
}
export default App;
Итак, я знаю, что должен использовать метод жизненного цикла shouldComponentUpdate, если я хочу повторно отобразить. Как я могу повторно отобразить тот же компонент, если я хочу получить прогноз погоды в других городах? Или мне нужно передать состояния в качестве реквизита другому компоненту, а затем я должен получить api? Нужна помощь!
Комментарии:
1. Если вы задаете состояние, компонент должен повторно визуализироваться без необходимости делать с ним что-либо еще. Вы пробовали просто установить состояние с помощью новой информации о городе?
2. что это значит? всякий раз, когда произойдет изменение состояния, ваш компонент будет повторно отображаться..
3. Каждый раз, когда вы вызываете
this.setState
компонент, он будет повторно отображаться, если изменение DOM должно происходить в соответствии с данными, которые были изменены.4. Ах, я вижу вашу проблему, у вас есть только вызов API
componentDidMount
, поэтому он будет извлекать данные только при монтировании вашего компонента. Что вы захотите сделать, так это также включить егоcomponentDidUpdate
. Чтобы попытаться избежать избыточного кода, вы можете поместить его в собственный метод.5. @Nick итак, выборка должна быть внутри componentDidMount ?
Ответ №1:
Проблема, с которой вы сталкиваетесь, заключается не в том, что вам нужно повторно отобразить свой компонент, а в том, что вам нужно использовать API погоды при обновлении вашего состояния. Вы можете сделать это, убедившись, что вы вызываете свой API в методе componentDidUpdate
жизненного цикла. Вот некоторый обновленный код, который делает это (и абстрагирует вызов API, чтобы избежать избыточного кода).
fetchWeatherData() {
fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${this.state.lat}amp;lon=${this.state.long}amp;units=metricamp;exclude=alertsamp;appid={api_key}`
)
.then((res) => res.json())
.then(
(result) => {
this.setState({
currentWeatherData: result.current,
hourlyWeatherData: result.hourly[0],
dailyWeatherData: result.daily[0]
});
},
(error) => {
console.log(error);
this.setState({
error
});
}
);
}
componentDidMount() {
this.fetchWeatherData();
}
componentDidUpdate(_, prevState) {
if (prevState.lat !== this.state.lat || prevState.long !== this.state.long) {
this.fetchWeatherData();
}
}
В конструкторе обязательно выполните привязку fetchWeatherData
к this
.
constructor(props) {
// Existing constructor code here
this.fetchWeatherData = this.fetchWeatherData.bind(this);
}
Комментарии:
1. он выбрасывает
Unhandled Runtime Error TypeError: Cannot read property '0' of undefined
.2. Возможно, вам придется выполнить некоторые действия по устранению неполадок внутри возврата вызова fetch. Эта ошибка говорит мне
result.hourly
, что в какой-то момент либо нет, либо нетresult.daily
возврата от вашего вызова fetch. Существует ли другой тип возврата из API, если, например, вы предоставляете ему неверный lat / lon?3. (Также убедитесь, что ключ API включен правильно. Прямо сейчас я скопировал его так, как у вас было в вопросе, но, похоже, это должна быть литеральная переменная шаблона
${api_key}
, а не то, чем она является в настоящее время (без знака доллара)4. Я, очевидно, ввел правильный ключ api. Но я думаю, что могут возникнуть некоторые проблемы с ответом, когда я выберу этот вариант. Над этим нужно поработать.
5. Ваш код здесь создает бесконечный цикл, и мой друг обратил на это внимание.