我的目标是当用户在输入中键入内容时发出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>
);
}
}
答案 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
的值总是不同的。这是发生了什么:
上下文进行搜索查询。
上下文状态会使用新数据进行更新,这将导致所有使用者重新呈现。
在上下文使用者useEffect
中,上下文值已被
已更新并调用setTimeout
,这将要求进行另一次搜索
在上下文提供程序中在500毫秒内完成。
解决方案是保持上下文值相同的对象,同时仅更新其属性。可以通过将所有必要的属性放在上下文状态中来完成此操作。这样:
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