Реагировать на асинхронную выборку - PullRequest
2 голосов
/ 03 апреля 2020

Использование React и React-Dom CDN 16

Я новичок в React и пытаюсь создать компонент панели мониторинга, который принимает значение одной из трех кнопок в компоненте Buttons и отправляет значение в компонент List. , Компонент List извлекает данные из API и отображает результаты.

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

Вот код.

const { useState, useEffect } = React

const App = props => {
  return (
    <div className="app-content">
      <Dashboard />
    </div>
  );
};

const Dashboard = props => {

  const [timespan, setTimespan] = useState('week');
  const changeTime = time => setTimespan(time);

  return(
    <div>
      <p>{timespan}</p> // this state updates when the buttons are clicked
      <Buttons onUpdate={changeTime} />
      <List timespan={timespan}/>
    </div>
  );

};

const Buttons = props => {
  return (
    <div>
      <button onClick={props.onUpdate.bind( this, 'week' )}>
        week
      </button>
      <button onClick={props.onUpdate.bind( this, 'month' )}>
        month
      </button>
      <button onClick={props.onUpdate.bind( this, 'all' )}>
        all
      </button>
    </div>
  );
};

const List = props => {

  const timespan = props.timespan;
  const homepage = `${location.protocol}//${window.location.hostname}`;
  const action = `${homepage}?fetchDataset=1&timespan=${timespan}`; 
  // if I console.log(action) here the URL is updated correctly 

  const [error, setError] = useState(null);
  const [isLoaded, setIsLoaded] = useState(false);
  const [obj, setObj] = useState([]);

  useEffect(() => {
    fetch(action)
    .then(res => res.json())
    .then(
      (result) => { // if I console.log(result) here I only get a response at initialization 
        setIsLoaded(true);
        setObj(result);
      },
      (error) => {
        setIsLoaded(true);
        setError(error);
      }
    )
  }, []);

  if (error) {
    return <div>Error: {error.message}</div>;
  } else if (!isLoaded) {
    return <div>Loading...</div>;
  } else {
    return (
      <div> 
        // my API returns "timespan is: $timespan", but this is only ever "week" because that's the initial state of the timespan 
        {obj}
      </div>
    );
  };
};

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

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

Я действительно ценю любую помощь. Спасибо!

1 Ответ

1 голос
/ 03 апреля 2020

вам нужно добавить timeSpan (или action) к вашему useEffect массиву зависимостей:

useEffect(() => {
    fetch(action)
      .then(res => res.json())
      .then(
        result => {
          setIsLoaded(true);
          setObj(result);
        },
        error => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, [timeSpan]); // [action] will also solve this

Таким образом, эффект будет знать, что он должен запускаться каждый раз, когда timeSpan prop меняется.

Передавая пустой массив зависимостей, вы указываете, что эффект запускается только один раз - когда компонент смонтирован.

...