Реагируйте useEffect и возвращайте render - PullRequest
1 голос
/ 08 января 2020

У меня есть useEffect с fetch, и я хотел бы сначала отобразить его, поскольку сначала он запускает case else, а затем запускает useEffect. Который показывает другой случай, а затем сообщения при просмотре страницы. Есть ли способ сделать сначала useEffect? ​​

const [posts, setPosts] = useState([]);

useEffect(() => {
  const data = await fetch('https://localhost:1111/api/posts', {
    credentials: 'include'
  });
  const response = await data.json();
  setPosts(response);
}, []);

return (
  <div>
    {posts.length > 0 ? (
      posts.map(post => (
        <Post key={post.id} onUpdate={() => handleUpdate()} post={post} />
      ))
    ) : (
      <p>No posts</p>
    )}
  </div>
);

Ответы [ 3 ]

2 голосов
/ 08 января 2020

Вы можете получить этот результат, но вам нужно будет сделать это по-другому.

Когда ваш компонент рендерится в первый раз, запустится вся функция, а затем страница будет обновлена ​​на основе на что вернулась твоя функция. Это происходит более или менее синхронно. Ваши эффекты запускаются только после того, как он отрендерен. Изменить порядок этого невозможно: рендеринг всегда первый, эффекты всегда после рендеринга.

Так что, если вы не хотите, чтобы что-либо отображалось, пока этот эффект не завершится, вам нужно вернуть ноль от рендера. Затем, когда выборка завершена, вы обновляете состояние, в результате чего он снова отображается, на этот раз не с нулевым значением.

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

const [posts, setPosts] = useState(null);

useEffect(() => {
  (async () => {
    const data = await fetch('https://localhost:1111/api/posts', {
      credentials: 'include'
    });
    const response = await data.json();
    setPosts(response);
  })();
}, []);

if (posts === null) {
  return null;
}

return (
  <div>
    {posts.length > 0 ? (
      posts.map(post => (
        <Post key={post.id} onUpdate={() => handleUpdate()} post={post} />
      ))
    ) : (
      <p>No posts</p>
    )}
  </div>
);
0 голосов
/ 08 января 2020

Вы используете useEffect как componentDidMount, потому что вы предоставляете пустой массив в качестве зависимости. Как следует из названия, он вызывается после того, как ваш компонент сначала рендерит.

Таким образом, чтобы ответить на ваш вопрос, нет, вы не можете отобразить результат извлечения как первый. Вы можете использовать компонент Loader для улучшения UX и подождать, пока ваши данные будут извлечены.

Или вы можете получить свои данные в родительском компоненте и передать их в качестве реквизита, чтобы вы могли сначала выполнить рендеринг с полученными данными. .

0 голосов
/ 08 января 2020

Вы можете установить для сообщений значение null по умолчанию, а не пустой массив. Тогда ничего не рендерим (или спиннер), если posts равно null. Это предотвратит мигание «нет сообщений» во время извлечения данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...