Почему изменение состояния моего компонента ReactJS не запускает повторную визуализацию?

#reactjs #state #rerender

#reactjs #состояние #повторный рендеринг

Вопрос:

У меня есть компонент класса ReactJS со следующим конструктором:

 constructor(props) {
      super(props);
      this.state = {
        // Defaults (London)
        latitude: 51.509865,
        longitude: -0.118092,
        userAddress: null
      };
      this.getCoordinates = this.getCoordinates.bind(this);
    }
 

Затем я пытаюсь получить координаты пользователя и сохранить их в состоянии:

     // On component initialisation, get the users location in co-ordinates and set the state accordingly
    componentDidMount() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(this.getCoordinates, this.handleLocationError);
      } else {
        alert("Geolocation is not supported by this browser.");
      }
    }
    
    getCoordinates(position) {
      this.setState({
        latitude: position.coords.latitude,
        longitude: position.coords.longitude
      })
    }
 

Я передаю координаты пользователей дочерней функции, которая отображает на экране карту погоды с текущей температурой в местоположении пользователя.

Функция рендеринга:

     render() {
      (some code)
        <div><CreateWeatherCard lat={this.state.latitude} long={this.state.longitude} /></div>
       (some code)
    }
 

Функция для создания карты погоды использует координаты пользователей в качестве реквизитов, использует их в вызове API POST-запроса и затем должна отображать температуру в текущем местоположении пользователя на экране

 function CreateWeatherCard(props) {
  const classes = cardStyles();
  let [currentTemp, setCurrentTemp] = React.useState([]);

    // console.log(props.lat)

  React.useEffect(() => {
    async function fetchData() {
      const request = await axios.post('/weatheratcoords/', {
        lat: props.lat,
        long: props.long
      });
      // console.log(request);
      // console.log(request.data.currentTemp);
      setCurrentTemp(request.data.currentTemp);
      return request;
    }
    fetchData();
  }, []);

   return
     blah blah
 

Но поскольку я запускаю серверную часть локально, я вижу, что получаю только один вызов API с координатами по умолчанию из конструктора состояния. Я никогда не получаю второй вызов с обновленными координатами. Я знаю, что состояние успешно обновляется, поскольку я вижу свои собственные координаты lat / long в состоянии компонента в инструментах React dev.

Я понимаю, что изменение состояния должно вызвать повторный рендеринг, который, в свою очередь, должен создать новый вызов API с правильными пользовательскими координатами? Может кто-нибудь помочь мне понять, почему этого не происходит? Спасибо!

Ответ №1:

Существует проблема с вашим useEffect() .

Вы написали это так:

  React.useEffect(() => {
    async function fetchData() {
      const request = await axios.post('/weatheratcoords/', {
        lat: props.lat,
        long: props.long
      });
      // console.log(request);
      // console.log(request.data.currentTemp);
      setCurrentTemp(request.data.currentTemp);
      return request;
    }
    fetchData();
  }, []);
 

Второй параметр — пустой массив, что означает useEffect() , что он будет выполнен только один раз.


Решение

Поскольку вы передаете значения с использованием реквизита дочернему компоненту, поэтому при изменении реквизита useEffect() выполняется. Для этого передайте реквизиты внутри массива в вашем useEffect() качестве второго параметра.

Сделайте это так:

  React.useEffect(() => {
    async function fetchData() {
      const request = await axios.post('/weatheratcoords/', {
        lat: props.lat,
        long: props.long
      });
      // console.log(request);
      // console.log(request.data.currentTemp);
      setCurrentTemp(request.data.currentTemp);
      return request;
    }
    fetchData();
  }, [props]);
 

Комментарии:

1. Большое вам спасибо. Это решило проблему. Я проведу еще несколько исследований функции useEffect, чтобы убедиться, что я использую ее правильно в будущем! Спасибо за краткое объяснение.