如何解决搜索框反应中的异步行为

how to solve asynchronous behaviour in search Box react

所以我正在尝试使用 useState 和 useEffect 实现一个搜索框。我们有一个对象数组,想根据我们的搜索词过滤它。这是我的实现:

import React, {useEffect, useState} from "react";

const array = [
    { key: '1', type: 'planet', value: 'Tatooine' },
    { key: '2', type: 'planet', value: 'Alderaan' },
    { key: '3', type: 'starship', value: 'Death Star' },
    { key: '4', type: 'starship', value: 'CR90 corvette' },
    { key: '5', type: 'starship', value: 'Star Destroyer' },
    { key: '6', type: 'person', value: 'Luke Skywalker' },
    { key: '7', type: 'person', value: 'Darth Vader' },
    { key: '8', type: 'person', value: 'Leia Organa' },
];

let available = []


const Setup = () => {
    const [state, setState] = useState('');
    
    useEffect(() => {
        available = array.filter(a => a.value.startsWith(state));
    },[state])

    const show = state ? available : array;

    return <>
        <input value={state} onChange={e => setState(e.target.value)} type="text" className="form"/>
        {show.map(a => {
            return <Data id={a.key} key={parseInt(a.key)} value={a.value} type={a.type}/>
        })}
    </>
}

const Data = (props) => {
    return <>
    <div>
        <p>{props.value}</p>
    </div>

    </>
}



export default Setup;

当我们为搜索框提供有效的搜索词时(如 'T'),问题就开始了。我希望它相应地改变输出(只显示 'Tatooine')但输出没有改变。 同时,如果您在搜索词中添加另一个字符(如 'a',这会将我们的搜索词设置为 'Ta'),它将输出预期的结果。换句话说,搜索词不是同步应用的。你知道为什么吗

您只需将 toLowerCase 方法添加到您的过滤器函数中。就像这样:

import React, { useEffect, useState } from "react";

const array = [
  { key: "1", type: "planet", value: "Tatooine" },
  { key: "2", type: "planet", value: "Alderaan" },
  { key: "3", type: "starship", value: "Death Star" },
  { key: "4", type: "starship", value: "CR90 corvette" },
  { key: "5", type: "starship", value: "Star Destroyer" },
  { key: "6", type: "person", value: "Luke Skywalker" },
  { key: "7", type: "person", value: "Darth Vader" },
  { key: "8", type: "person", value: "Leia Organa" }
];

let available = [];

const Setup = () => {
  const [state, setState] = useState("");

  useEffect(() => {
    available = array.filter((a) => a.value.toLowerCase().startsWith(state));
  }, [state]);

  const show = state ? available : array;

  return (
    <>
      <input
        value={state}
        onChange={(e) => setState(e.target.value)}
        type="text"
        className="form"
      />
      {show.map((a) => {
        return (
          <Data
            id={a.key}
            key={parseInt(a.key)}
            value={a.value}
            type={a.type}
          />
        );
      })}
    </>
  );
};

const Data = (props) => {
  return (
    <>
      <div>
        <p>{props.value}</p>
      </div>
    </>
  );
};

export default Setup;

这是工作示例:here

您可以简单地拉出 useEffect。

import React, { useState } from 'react';

const array = [
    { key: '1', type: 'planet', value: 'Tatooine' },
    { key: '2', type: 'planet', value: 'Alderaan' },
    { key: '3', type: 'starship', value: 'Death Star' },
    { key: '4', type: 'starship', value: 'CR90 corvette' },
    { key: '5', type: 'starship', value: 'Star Destroyer' },
    { key: '6', type: 'person', value: 'Luke Skywalker' },
    { key: '7', type: 'person', value: 'Darth Vader' },
    { key: '8', type: 'person', value: 'Leia Organa' },
];

let available = [];

const Setup = () => {
    const [state, setState] = useState('');

    available = array.filter(a => a.value.startsWith(state));

    const show = state ? available : array;

    return (
        <>
            <input
                value={state}
                onChange={e => setState(e.target.value)}
                type='text'
                className='form'
            />
            {show.map(a => {
                return (
                    <Data
                        id={a.key}
                        key={parseInt(a.key)}
                        value={a.value}
                        type={a.type}
                    />
                );
            })}
        </>
    );
};

const Data = props => {
    return (
        <>
            <div>
                <p>{props.value}</p>
            </div>
        </>
    );
};

export default Setup;

useEffect 挂钩在组件挂载、重新呈现或卸载时触发。在您的情况下,由于 state 的更改,搜索字段的更改会导致重新呈现。这会导致您的 useEffect 在 状态更改后触发 并且为时已晚,无法满足您的需求。

如果您在字段中输入“Ta”,您会发现它有效,但搜索似乎落后了一步。

您可以在渲染时简单地删除 useEffect 和过滤的使用。这意味着您还可以删除围绕 availableshow 变量的整个逻辑:

const Setup = () => {
  const [state, setState] = useState("");

  return (
    <>
      <input
        value={state}
        onChange={(e) => setState(e.target.value)}
        type="text"
        className="form"
      />
      {array
        .filter((a) => a.value.startsWith(state))
        .map((a) => (
          <Data
            id={a.key}
            key={parseInt(a.key, 10)}
            value={a.value}
            type={a.type}
          />
        ))}
    </>
  );
};

Using the Effect Hook 文档中有一些很好的信息。

这个一定要解决

import React, { useEffect, useState } from "react";
    
    const array = [
      { key: "1", type: "planet", value: "Tatooine" },
      { key: "2", type: "planet", value: "Alderaan" },
      { key: "3", type: "starship", value: "Death Star" },
      { key: "4", type: "starship", value: "CR90 corvette" },
      { key: "5", type: "starship", value: "Star Destroyer" },
      { key: "6", type: "person", value: "Luke Skywalker" },
      { key: "7", type: "person", value: "Darth Vader" },
      { key: "8", type: "person", value: "Leia Organa" }
    ];
    
    const Setup = () => {
      const [state, setState] = useState("");
      const [available, setAvailable] = useState(array);
    
      useEffect(() => {
        setAvailable(array.filter((a) => a.value.startsWith(state)));
      }, [state]);
    
      return (
        <>
          <input
            value={state}
            onChange={(e) => setState(e.target.value)}
            type="text"
            className="form"
          />
          {available.map((a) => {
            return (
              <Data
                id={a.key}
                key={parseInt(a.key)}
                value={a.value}
                type={a.type}
              />
            );
          })}
        </>
      );
    };
    
    const Data = (props) => {
      return (
        <>
          <div>
            <p>{props.value}</p>
          </div>
        </>
      );
    };
    
    export default Setup;