В React Hook useEffect отсутствует зависимость: «контекст». Либо включите его, либо удалите массив зависимостей - PullRequest
0 голосов
/ 16 февраля 2020

Моя цель - сделать запрос API, когда пользователь что-то вводит при вводе. Я получаю данные успешно. Однако компонент дважды перерисовывается и выдает мне это предупреждение. Если я включаю «контекст», я получаю бесконечное число l oop. Вот мой код:

Компонент. js:


const SearchBox = () => {
  const [searchTerm, setSearchTerm] = useState("");
  const { handleSearch, searchResults } = useContext(MovieContext);

  console.log(searchResults);

  useEffect(() => {
    let timer;
    timer = setTimeout(() => {
      handleSearch(searchTerm);
    }, 500);

    return () => clearTimeout(timer);
  }, [searchTerm]);

  const renderResults = () => {
    if (searchResults.length > 0) {
      searchResults.map(result => {
        return (
          <div key={result.Title}>
            <img src={result.Poster} alt={result.Title} />;
          </div>
        );
      });
    }
    return;
  };

  return (
    <>
      <label>
        <b>Search</b>
      </label>
      <input
        className="input"
        value={searchTerm}
        onChange={e => setSearchTerm(e.target.value)}
      />
      <div className="dropdown is-active">
        <div className="dropdown-menu">
          <div className="dropdown-content results">{renderResults()}</div>
        </div>
      </div>
    </>
  );
};

Поверх этого context.searchResults не определено, хотя я установил начальное значение как пустое массив. Я хотел знать, что вызвало это. Что я делаю неправильно? Вот мой код контекста ниже:

Context. js:

const Context = React.createContext("");

export class MovieStore extends Component {
  constructor(props) {
    super(props);
    this.state = {
      searchResults: [],
      handleSearch: this.handleSearch
    };
  }

  handleSearch = async term => {
    try {
      if (term !== "") {
        const response = await axios.get("http://www.omdbapi.com/", {
          params: {
            apikey: apikey,
            s: term
          }
        });
        this.setState({ searchResults: response.data.Search });
      }
    } catch (error) {
      console.log(error);
    }
  };

  render() {
    return (
      <Context.Provider value={this.state}>
        {this.props.children}
      </Context.Provider>
    );
  }
}

1 Ответ

2 голосов
/ 16 февраля 2020

Точно то же самое о бесконечном l oop упоминается в React документах здесь . Таким образом, причина бесконечного l oop заключается в том, что в функции рендеринга контекста вы создаете новое значение каждый вызов времени рендеринга.

  render() {
    return (
      <Context.Provider
        // ! value object creates every time render is called - it's bad
        value={{ ...this.state, handleSearch: this.handleSearch }}
      >
        {this.props.children}
      </Context.Provider>
    );
  }

Это вызывает каждый потребитель должен обновляться при обновлении состояния контекста. Итак, если вы поместите context в массив зависимостей useEffect, в конечном итоге это приведет к бесконечному l oop, потому что значение context всегда отличается. Вот что происходит:

  1. Контекст выполняет поисковый запрос.

  2. Обновление состояния контекста с новыми данными, что приводит к повторному отображению всех потребителей.

  3. В контексте потребителя useEffect видит, что значение контекста было обновлено, и вызывает setTimeout, который вызовет другой поиск в поставщике контекста через 500 мс.

  4. Потребитель вызывает контекст для создания другого поискового запроса, и мы получаем бесконечное l oop!

Решение состоит в том, чтобы сохранить значение контекста в том же объекте, при этом обновляя только его свойства. Это можно сделать, поместив все необходимые свойства в контекстное состояние. Вот так:

export class MovieStore extends Component {
  handleSearch = async term => {
    try {
      if (term !== "") {
        const response = await axios.get("http://www.omdbapi.com/", {
          params: {
            apikey: "15bfc1e3",
            s: term
          }
        });
        this.setState({ searchResults: response.data.Search });
      }
    } catch (error) {
      console.log(error);
    }
  };

  state = {
    searchResults: [],
    handleSearch: this.handleSearch // <~ put method directly to the state
  };

  render() {
    return (
      <Context.Provider value={this.state}> // <~ Just returning state here
        {this.props.children}
      </Context.Provider>
    );
  }
}

Надеюсь, это поможет <3 </p>

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