Реагируйте на рендеринг компонента дважды при использовании ловушки useState - PullRequest
1 голос
/ 20 апреля 2020

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

enter image description here

Я вставил console.log перед возвратом компонента, чтобы увидеть, сколько раз мой компонент рендерился.

Всякий раз, когда я удаляю ловушку useState, мое приложение рендерится только один раз, как я полагаю, должно быть. Любое руководство о том, почему это происходит, приветствуется

import React, { useState, useEffect } from 'react';

const ListItem = ({ title, url, author, num_comments, points }) => {
  return (
    <div>
      <span>
        <a href={url} target='_blank' rel='noopener noreferrer'>
          {title}
        </a>{' '}
        by {author}
      </span>
      <br />
      <span>Comments: {num_comments}</span>
      <br />
      <span>Points: {points}</span>
      <hr />
    </div>
  );
};

const List = ({ list }) => {
  return list.map(({ objectID, ...item }) => (
    <ListItem key={objectID} {...item} />
  ));
};

const Search = ({ search, onSearch }) => {
  return (
    <div>
      <label htmlFor='search'>Search: </label>
      <input id='search' type='text' value={search} onChange={onSearch} />
      <p>
        Searching for <strong>{search}</strong>
      </p>
    </div>
  );
};

const App = () => {
  const stories = [
    {
      title: 'React',
      url: 'https://reactjs.org/',
      author: 'Jordan Walke',
      num_comments: 3,
      points: 4,
      objectID: 0,
    },
    {
      title: 'Redux',
      url: 'https://redux.js.org/',
      author: 'Dan Abramov, Andrew Clark',
      num_comments: 2,
      points: 5,
      objectID: 1,
    },
  ];

  const [search, setSearch] = useState(localStorage.getItem('search') || '');

  useEffect(() => {
    localStorage.setItem('search', search);
  }, [search]);

  const handleSearch = (event) => {
    setSearch(event.target.value);
  };

  console.log('rendered');

  return (
    <div className='App'>
      <h1>My Hacker Stories</h1>
      <Search search={search} onSearch={handleSearch} />
      <hr />
      <List
        list={stories.filter((story) =>
          story.title.toLowerCase().includes(search.toLowerCase())
        )}
      />
    </div>
  );
};

export default App;

Ответы [ 3 ]

2 голосов
/ 20 апреля 2020

Проверьте это: https://github.com/facebook/react-devtools/issues/1297

"Неожиданный повторный рендеринг" на самом деле не вызван специально useEffect - скорее, именно так проверяет DevTools " "перехватывает значения путем повторного рендеринга компонента функции в отдельности.

Хотя я понимаю, что в некоторых случаях непредвиденные отрисовки могут указывать на проблемы, этот конкретный не должен быть проблемой по нескольким причинам:

Визуализация не является рекурсивной. (Дочерние компоненты не отображаются.) Рендеринг происходит только для пользователей с установленным DevTools, и даже тогда - влияет только на один компонент (который в данный момент выбран в дереве). Рендеринг не имеет побочных эффектов (например, DOM не будет обновляться).

2 голосов
/ 20 апреля 2020

Ваш 'setSearch' обновляет vue для поля ввода, а затем ваш 'useEffect' снова обновляет его при изменении поиска.

Удалите useEffect

Затем

const handleSearch = (event) => {
    setSearch(event.target.value);
    localStorage.setItem('search', event.target.value)
  }

Вот ссылка на песочницу: https://codesandbox.io/s/dawn-night-h2xiz?file= / src / App. js

Это действительно не решит проблему, но, вероятно, позволит избежать некоторых проблем в будущем.

Двойной рендеринг должен происходить только в режиме разработки, а не в производстве. Смотрите ответ Дана Абрамова здесь: https://github.com/facebook/react/issues/15074

0 голосов
/ 20 апреля 2020

Я согласен с @ denislexi c, вот один из способов решения проблемы.

Вместо

useEffect(() => {
  localStorage.setItem('search', search);
}, [search]);

const handleSearch = (event) => {
  setSearch(event.target.value);
};

Давайте сделаем следующее:

const handleSearch = (event) => {
  const search = event.target.value;
  setSearch(search);
  localStorage.setItem('search', search);
};

Это выполняет те же 2 задачи (сохранение в состояние и localStorage) в одной подпрограмме вместо 2. Подсказка: useEffect вызывает повторную визуализацию

Надежда, которая помогает.

Приветствия! 101

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