React Hook useEffect缺少依赖项:“上下文”。包括它或删除依赖项数组

时间:2020-02-16 16:34:52

标签: reactjs react-hooks

我的目标是当用户在输入中键入内容时发出API请求。我正在成功获取数据。但是,该组件重新渲染两次,并向我发出此警告。如果我包含“上下文”,那么我将陷入无限循环。这是我的代码:

Component.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 个答案:

答案 0 :(得分:2)

React文档here中提到了关于无限循环的完全相同的事情。因此,无限循环的原因是,在上下文渲染功能中,您创建了 new 次调用渲染。

  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的依赖项数组中,最终将导致无限循环,因为context的值总是不同的。这是发生了什么:

  1. 上下文进行搜索查询。

  2. 上下文状态会使用新数据进行更新,这将导致所有使用者重新呈现。

  3. 在上下文使用者useEffect中,上下文值已被 已更新并调用setTimeout,这将要求进行另一次搜索 在上下文提供程序中在500毫秒内完成。

  4. 消费者调用上下文进行另一个搜索查询,我们陷入了无限循环!

解决方案是保持上下文值相同的对象,同时仅更新其属性。可以通过将所有必要的属性放在上下文状态中来完成此操作。这样:

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