为什么在这个React 18搜索框中,onKeyUp事件返回undefined?

huangapple go评论83阅读模式
英文:

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)这一行没有记录任何内容。

问题

  1. 我做错了什么?
  2. 修复此问题的最可靠方法是什么?
英文:

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 &#39;../../icons/magnifier.svg&#39;;
import { useEffect, useState } from &#39;react&#39;;
import axios from &#39;axios&#39;;

function Searchbox({ movie }) {

 const API_URL = &#39;https://api.themoviedb.org/3&#39;;
 const [searchInput, setSearchInput] = useState(&#39;&#39;);
 const [results, setResults] = useState([]);
 const timeOutInterval = 1000;

const doMovieSearch = async (e) =&gt; {
setSearchInput(e.target.value);

if (searchInput.length &gt;= 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 (
	&lt;form className=&quot;search_form w-100 mx-auto mt-2 mt-md-0&quot;&gt;
	  &lt;div className=&quot;input-group&quot;&gt;
		&lt;input className=&quot;form-control search-box&quot; type=&quot;text&quot; value={searchInput} onKeyUp={debounceMovieSearch} placeholder=&quot;Search movies...&quot; /&gt;
		&lt;div className=&quot;input-group-append&quot;&gt;
		  &lt;button className=&quot;btn&quot; type=&quot;button&quot;&gt;
			&lt;Magnifier /&gt;
		  &lt;/button&gt;
		&lt;/div&gt;
	  &lt;/div&gt;
	&lt;/form&gt;
  );
}

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

  1. What am I doing wrong?
  2. 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) =&gt; {
  const inputValue = e.target.value;
  setSearchInput(inputValue);

  if (inputValue.length &gt;= 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 = () =&gt; {
  setTimeout(() =&gt; {
    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 &#39;../../icons/magnifier.svg&#39;;
    import { useState } from &#39;react&#39;;
    import axios from &#39;axios&#39;;
    
    function Searchbox({ movie }) {
    
      const API_URL = &#39;https://api.themoviedb.org/3&#39;;
      const [searchInput, setSearchInput] = useState(&#39;&#39;);
      const [results, setResults] = useState([]);
      const timeOutInterval = 1000;
    
      const doMovieSearch = async (e) =&gt; {
        setSearchInput(e.target.value);
    
        if (e.target.value.length &gt;= 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) =&gt; {
        setTimeout(() =&gt; doMovieSearch(e), timeOutInterval);
      }
    
    return (
        &lt;form className=&quot;search_form w-100 mx-auto mt-2 mt-md-0&quot;&gt;
          &lt;div className=&quot;input-group&quot;&gt;
          &lt;input className=&quot;form-control search-box&quot; type=&quot;text&quot; defaultValue={searchInput} onKeyUp={debounceMovieSearch} placeholder=&quot;Search movies...&quot; /&gt;
            &lt;div className=&quot;input-group-append&quot;&gt;
              &lt;button className=&quot;btn&quot; type=&quot;button&quot;&gt;
                &lt;Magnifier /&gt;
              &lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/form&gt;
     );
    }
    export default Searchbox;

Additionally, I&#39;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&#39;s input, not the previous state of searchInput.


</details>



huangapple
  • 本文由 发表于 2023年7月17日 20:39:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76704549.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定