英文:
Why does the onKeyUp event return undefined in this React 18 search box?
问题
我一直在使用**React 18**和**The Movie Database (TMDB) API**开发单页面应用。
我目前正在处理*搜索功能*。
在`Searchbox.jsx`组件中,我有:
```jsx
import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
import { useEffect, useState } from 'react';
import axios from 'axios';
function Searchbox({ movie }) {
const API_URL = 'https://api.themoviedb.org/3';
const [searchInput, setSearchInput] = useState('');
const [results, setResults] = useState([]);
const timeOutInterval = 1000;
const doMovieSearch = async (e) => {
setSearchInput(e.target.value);
if (searchInput.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${searchInput}`, {
params: {
api_key: process.env.REACT_APP_API_KEY
}
});
setResults(results);
console.log(results);
}
}
return (
<form className="search_form w-100 mx-auto mt-2 mt-md-0">
<div className="input-group">
<input className="form-control search-box" type="text" value={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
<div className="input-group-append">
<button className="btn" type="button">
<Magnifier />
</button>
</div>
</div>
</form>
);
}
export default Searchbox;
问题
出于我无法理解的原因,进行搜索时出现以下错误:
Cannot read properties of undefined (reading 'target').
这个错误出现在setSearchInput(e.target.value)
这一行。
console.log(results)
这一行没有记录任何内容。
问题
- 我做错了什么?
- 修复此问题的最可靠方法是什么?
英文:
I have been working on an SPA with React 18 and The Movie Database (TMDB) API.
I am currently working on a search functionality.
In the Searchbox.jsx
component I have:
import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
import { useEffect, useState } from 'react';
import axios from 'axios';
function Searchbox({ movie }) {
const API_URL = 'https://api.themoviedb.org/3';
const [searchInput, setSearchInput] = useState('');
const [results, setResults] = useState([]);
const timeOutInterval = 1000;
const doMovieSearch = async (e) => {
setSearchInput(e.target.value);
if (searchInput.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${searchInput}`, {
params: {
api_key: process.env.REACT_APP_API_KEY
}
});
setResults(results);
console.log(results);
}
}
return (
<form className="search_form w-100 mx-auto mt-2 mt-md-0">
<div className="input-group">
<input className="form-control search-box" type="text" value={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
<div className="input-group-append">
<button className="btn" type="button">
<Magnifier />
</button>
</div>
</div>
</form>
);
}
export default Searchbox;
The problem
For a reason I have been unable to figure out, doing a search fails with this error:
> Cannot read properties of undefined (reading 'target').
The error is at the line setSearchInput(e.target.value)
.
The line console.log(results)
does not log anything.
Questions
- What am I doing wrong?
- What is the most reliable way to fix this issue?
答案1
得分: 1
为了解决这个问题,您可以使用功能性更新与 setSearchInput 以确保始终使用最新的 searchInput 值。以下是修改后的代码:
const doMovieSearch = async (e) => {
const inputValue = e.target.value;
setSearchInput(inputValue);
if (inputValue.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${inputValue}`, {
params: {
api_key: process.env.REACT_APP_API_KEY
}
});
setResults(results);
console.log(results);
}
}
const debounceMovieSearch = () => {
setTimeout(() => {
doMovieSearch({ target: { value: searchInput } }); // 传递一个带有最新 searchInput 值的模拟事件对象
}, timeOutInterval);
}
希望对您有所帮助。
英文:
To fix this issue, you can use a functional update with setSearchInput to ensure that you're always using the latest value of searchInput. Here's the modified code:
const doMovieSearch = async (e) => {
const inputValue = e.target.value;
setSearchInput(inputValue);
if (inputValue.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie?query=${inputValue}`, {
params: {
api_key: process.env.REACT_APP_API_KEY
}
});
setResults(results);
console.log(results);
}
}
const debounceMovieSearch = () => {
setTimeout(() => {
doMovieSearch({ target: { value: searchInput } }); // Pass a mock event object with the latest searchInput value
}, timeOutInterval);
}
答案2
得分: 1
你需要将事件传递给debounceMovieSearch
,然后进一步传递给doMovieSearch
:
import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
import { useState } from 'react';
import axios from 'axios';
function Searchbox({ movie }) {
const API_URL = 'https://api.themoviedb.org/3';
const [searchInput, setSearchInput] = useState('');
const [results, setResults] = useState([]);
const timeOutInterval = 1000;
const doMovieSearch = async (e) => {
setSearchInput(e.target.value);
if (e.target.value.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie`, {
params: {
api_key: process.env.REACT_APP_API_KEY,
query: e.target.value
}
});
setResults(results);
}
}
const debounceMovieSearch = (e) => {
setTimeout(() => doMovieSearch(e), timeOutInterval);
}
return (
<form className="search_form w-100 mx-auto mt-2 mt-md-0">
<div className="input-group">
<input className="form-control search-box" type="text" defaultValue={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
<div className="input-group-append">
<button className="btn" type="button">
<Magnifier />
</button>
</div>
</div>
</form>
);
}
export default Searchbox;
另外,我对`doMovieSearch`中的条件做了小调整,使用`e.target.value.length`代替`searchInput.length`,因为我们要检查用户输入的长度,而不是`searchInput`的前一个状态。
<details>
<summary>英文:</summary>
You need to pass the event to debounceMovieSearch and pass it further to doMovieSearch:
import { ReactComponent as Magnifier } from '../../icons/magnifier.svg';
import { useState } from 'react';
import axios from 'axios';
function Searchbox({ movie }) {
const API_URL = 'https://api.themoviedb.org/3';
const [searchInput, setSearchInput] = useState('');
const [results, setResults] = useState([]);
const timeOutInterval = 1000;
const doMovieSearch = async (e) => {
setSearchInput(e.target.value);
if (e.target.value.length >= 3) {
const { data: { results } } = await axios.get(`${API_URL}/search/movie`, {
params: {
api_key: process.env.REACT_APP_API_KEY,
query: e.target.value
}
});
setResults(results);
}
}
const debounceMovieSearch = (e) => {
setTimeout(() => doMovieSearch(e), timeOutInterval);
}
return (
<form className="search_form w-100 mx-auto mt-2 mt-md-0">
<div className="input-group">
<input className="form-control search-box" type="text" defaultValue={searchInput} onKeyUp={debounceMovieSearch} placeholder="Search movies..." />
<div className="input-group-append">
<button className="btn" type="button">
<Magnifier />
</button>
</div>
</div>
</form>
);
}
export default Searchbox;
Additionally, I've made a small adjustment to the condition in doMovieSearch to use e.target.value.length instead of searchInput.length, as we want to check the length of the user's input, not the previous state of searchInput.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论