typescript 最惯用的方法是仅在依赖项从上一个值更改时运行React钩子

9gm1akwq  于 2022-12-24  发布在  TypeScript
关注(0)|答案(2)|浏览(146)

我有一个由ParentComponent和HelpSearchWindow组成的React应用程序。在ParentComponent的页面上,有一个按钮,可以让你打开一个包含HelpSearchWindow的窗口。HelpSearchWindow有一个输入字段和一个搜索按钮。当键入输入并单击搜索按钮时,运行搜索并将结果显示到窗口的表中。可以关闭窗口。我设置了react.useEffect()与依赖项[documentationIndexState.searchTerm]挂钩,以便仅在searchTerm改变时才运行搜索功能。
但是,窗口的行为并不像我预期的那样。**因为useEffect()在窗口关闭之后每次打开窗口时被调用,则它将再次运行搜索,而不管依赖性数组中的searchTerm是否相同。**因此,我又加了一个州 prop (prevSearchTerm)来存储最后搜索的项。这样,如果窗口被打开和关闭多次而没有设置新的searchTerm,没有重复的搜索运行。

我的问题是,是否有更惯用/React式的方法来实现这一点?也欢迎使用任何其他代码格式化指针

import {
    setSearchTerm,
} from 'documentationIndex.store';

interface Props {
    searchInput: string;
    setSearchInput: (searchInput: string) => void;
    prevSearchTerm: string;
    setPrevSearchTerm: (searchInput: string) => void;
}

export const HelpSearchWindow: React.FC<Props> = props => {
    const documentationIndexState = useSelector((store: StoreState) => store.documentationIndex);
    const dispatch = useDispatch();
    
    // Only run search if searchTerm changes
    React.useEffect(() => {
        async function asyncWrapper() {
            if (!documentationIndexState.indexExists) {
                // do some await stuff (need asyncWrapper because of this)
            }
            if (props.prevSearchTerm !== documentationIndexState.searchTerm) {
                // searching for a term different than the previous searchTerm so run search
                // store most recently used searchTerm as the prevSearchTerm
                props.setPrevSearchTerm(props.searchInput);
            }
        }
        asyncWrapper();
    }, [documentationIndexState.searchTerm]); 
    return (
        <input
            value={props.searchInput}
            onChange={e => props.setSearchInput(e.target.value)}
        />
        <button
            onClick={e => {
                e.preventDefault();
                dispatch(setSearchTerm(props.searchInput));
            }}
        >
            Search
        </button>
        <SearchTable
            rows={documentationIndexState.searchResults}
        />
    );
};

//--------- Parent Component----------------------------------------
const ParentComponent = React.memo<{}>(({}) => {
    const [searchInput, setSearchInput] = React.useState(''); // value inside input box
    const [prevSearchTerm, setPrevSearchTerm] = React.useState(''); // tracks last searched thing
    return(
        <HelpSearchWindow
            searchInput={searchInput}
            setSearchInput={setSearchInput}
            prevSearchTerm={prevSearchTerm}
            setPrevSearchTerm={setPrevSearchTerm}
        />
    );
});
ctzwtxfj

ctzwtxfj1#

从给定的上下文来看,useEffevt钩子的使用是多余的。您应该简单地使用一个单击处理函数并附加到按钮上。
click处理程序将把搜索项存储在组件本地,同时检查新的输入值是否不同,如果是,将更新状态并调用API。

jmo0nnb3

jmo0nnb32#

我假设您正在使用react-redux或react-redux/工具包
'createSelector'是来自reselect库的实用程序函数,它允许您创建“记忆”选择器,以便在Redux应用程序中进行有效的数据检索。记忆选择器是一个函数,它将为同一组输入返回相同的结果,如果输入没有更改,则无需重新计算结果。
下面是如何在Redux应用程序中使用“createSelector”的示例:

import { createSelector } from 'reselect';

// Selectors
const getUsers = state => state.users;
const getUserId = (_, props) => props.userId;

// Memoized selector
export const getUser = createSelector(
  [getUsers, getUserId],
  (users, userId) => users.find(user => user.id === userId)
);

在本例中,我们有两个选择器:getUsers选择状态的用户切片,getUserId接受第二个参数(组件的属性)并返回userId属性。
createSelector函数以一个输入选择器数组和一个transform函数作为参数,transform函数接收输入选择器的值作为参数,并返回转换后的数据。
在本例中,getUser选择器是一个记忆选择器,它从users数组返回具有指定userId的用户对象。如果users或userId值未更改,getUser将返回相同的结果,而无需重新计算。
然后可以在组件中使用getUser选择器,如下所示:

import { useSelector } from 'react-redux';
import { getUser } from './selectors';

function UserProfile(props) {
  const user = useSelector(state => getUser(state, props));
  return <div>{user.name}</div>;
}

相关问题