未捕获的类型错误:无法读取属性“值” ReactJS 中的 null

发布于 2025-01-10 21:07:30 字数 1202 浏览 0 评论 0原文

我正在尝试在 React 中创建一个搜索栏,通过 TMDB API 进行搜索,但遇到了一些问题。每当我在搜索栏中输入内容时,都会收到一条错误消息,指出无法读取 null 的属性(读取“值”),并且我不确定问题可能是什么以及为什么它返回为 null。 中的提及

 function Search() {
  const [searchQuery, setSearchQuery] = useState(""); 
  const [timeoutId, updateTimeoutId] = useState();

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target.value);
    const timeout = setTimeout(() => fetchData(e.target.value), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );
}

我称这是 searchInput 代码

const SearchInput = styled.input`
  color: black;
  font-size: 16px;
  font-weight: bold;
  border: none;
  outline: none;
  margin-left: 15px;
`;

I am trying to create a search bar in react that searches through TMDB API but I'm having some issues. Whenever I type into the search bar I get an error saying that Cannot read properties of null (reading 'value') and I'm not sure what the issue could be and why its returning as null. I call the mention in

 function Search() {
  const [searchQuery, setSearchQuery] = useState(""); 
  const [timeoutId, updateTimeoutId] = useState();

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target.value);
    const timeout = setTimeout(() => fetchData(e.target.value), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );
}

This is the searchInput code

const SearchInput = styled.input`
  color: black;
  font-size: 16px;
  font-weight: bold;
  border: none;
  outline: none;
  margin-left: 15px;
`;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

吾家有女初长成 2025-01-17 21:07:30

您可以尝试使用 可选链接 (<代码>?.)

function Search() {
  const [searchQuery, setSearchQuery] = useState(""); 
  const [timeoutId, updateTimeoutId] = useState();

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target?.value);
    const timeout = setTimeout(() => fetchData(e.target?.value), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );
}

You could try with optional chaining (?.)

function Search() {
  const [searchQuery, setSearchQuery] = useState(""); 
  const [timeoutId, updateTimeoutId] = useState();

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target?.value);
    const timeout = setTimeout(() => fetchData(e.target?.value), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );
}
预谋 2025-01-17 21:07:30

一旦超时从 Web API 返回,e.target.value 就不再存在。该函数已结束执行,e 参数将不再存在。

相反,请在 setTimeout 回调函数中尝试使用 useRef 而不是 e.target.value,这样当它返回时,它可以引用最新的更改。

像这样的东西:

 function Search() {
  const [searchQuery, setSearchQuery] = useState("");
  const [timeoutId, updateTimeoutId] = useState();

  const query = useRef(searchQuery);

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target.value);
    query.current = e.target.value;
    const timeout = setTimeout(() => fetchData(query.current), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );

e.target.value does not exist anymore once the timeout has come back from the web api. The function has ended its execution and the e argument won't exist anymore.

Instead, try useRef instead of e.target.value in your setTimeout callback function, so when it comes back, it can reference the latest changes.

Something like this:

 function Search() {
  const [searchQuery, setSearchQuery] = useState("");
  const [timeoutId, updateTimeoutId] = useState();

  const query = useRef(searchQuery);

  const fetchData = async (searchString) => {
    const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
    console.log(response);
  };

  const onTextChange = (e) => {
    clearTimeout(timeoutId);
    setSearchQuery(e.target.value);
    query.current = e.target.value;
    const timeout = setTimeout(() => fetchData(query.current), 500);
    updateTimeoutId(timeout);
  };

  return(
    <div> 
      <SearchBox>
      <SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
      </SearchBox></div>
  );
一袭白衣梦中忆 2025-01-17 21:07:30

再次查看您的代码后,我怀疑这是超时回调中的第二个事件访问,该事件访问已被取消。您应该在回调范围内保存对事件值的引用,这样就不会持久存在对事件对象的依赖。

const onTextChange = (e) => {
  const { value } = e.target;

  clearTimeout(timeoutId);

  setSearchQuery(value);
  const timeout = setTimeout(() => fetchData(value), 500);
  updateTimeoutId(timeout);
};

另外,仅供参考,除非您需要 timeoutId 作为状态的一部分来触发重新渲染或其他内容,否则更常见的是在此处使用 React 引用来存储对计时器 id 的引用。据我所知,您只需限制 fetchData 调用,无需触发不必要的渲染。

例子:

const timeoutIdRef = useRef();

useEffect(() => {
  // clear any running timeouts upon component unmount
  return () => clearTimeout(timeoutIdRef.current);
}, []);

...

const onTextChange = (e) => {
  const { value } = e.target;

  clearTimeout(timeoutIdRef.current);

  setSearchQuery(value);
  timeoutIdRef.current = setTimeout(() => fetchData(value), 500);
};

After taking another look at your code I suspect it's the second event access in the timeout callback that's since been nullified. You should save a reference to the event's value within the callback scope so there isn't a dependency on the event object persisting.

const onTextChange = (e) => {
  const { value } = e.target;

  clearTimeout(timeoutId);

  setSearchQuery(value);
  const timeout = setTimeout(() => fetchData(value), 500);
  updateTimeoutId(timeout);
};

Also, FYI, unless you need the timeoutId as part of state to trigger a rerender or something, it's more common to use a React ref here to store a reference to the timer id. From what I can tell you are simply throttling the fetchData call and there is no need to trigger unnecessary renders.

Example:

const timeoutIdRef = useRef();

useEffect(() => {
  // clear any running timeouts upon component unmount
  return () => clearTimeout(timeoutIdRef.current);
}, []);

...

const onTextChange = (e) => {
  const { value } = e.target;

  clearTimeout(timeoutIdRef.current);

  setSearchQuery(value);
  timeoutIdRef.current = setTimeout(() => fetchData(value), 500);
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文