useState 和自定义钩子模式

问题描述 投票:0回答:1

来自 Angular,我很难用 React 构建一个简单的演示,因为我遇到了无限循环和其他副作用。

我有一个

GamePage.tsx
(容器组件),用户可以从主页导航。加载此组件时,我使用 Tanstack 查询(包装在自定义挂钩中的代码)从 API 获取一些数据。 根据结果,我将结果存储在组件的 state 属性中,并用它显示一个子组件。

但是,虽然我认为存储从 API 返回的数据似乎是保存在组件状态中的一个不错的选择,但通过设置它会触发无限循环。 我是否必须在 GamePage.tsx 中创建另一个子组件才能使用/调用自定义挂钩?这似乎有点过于冗长,并且并没有真正带来好处,因为容器组件已经相当小了。 考虑到下面的情况(容器组件 -> 获取数据 -> 初始化子组件)我的解决方案中应该更改哪些内容以遵循“React 方式”?从文档中我找不到唯一/通用的答案。

定制挂钩

const useWordByDifficulty = ({ difficulty }: { difficulty: Difficulty }) => {    
    const wishedLength = mapDifficultyToLength(difficulty);

    return useQuery({
        queryKey: [],
        queryFn: () => httpFetch(`API_URL`)
    });
};

游戏页面.tsx

const GamePage = () => {
    const { state }: { state: { difficulty: Difficulty } } = useLocation();

    // While I think the state here might be a good choice, it triggers an infinite loop setting it in the code below 
    //const [gameWord, setGameWord] = useState<string | null>(null);
    
    let reqStatus: HttpResponseStatus | null = null;
    let gameWord: string | null = null;

    // useEffect(() => { <-- This is not permitted as useWordByDifficulty is a custom hook
        let active = true;        

        // The API is called twice
        const { data, error, isPending, isError } = useWordByDifficulty(state)
        if (active) {
            if (isPending) {
                reqStatus = 'isPending';
            } else if (isError) {
                reqStatus = 'isError';
            } else {
               // If I set the word here, I get an infinite loop as the component re-render
               // setGameWord(data);
                reqStatus = 'isSuccess';
            }
        }

        return () => {
            // cleanup
            active = false;
        }
    // }, [state]);


    return (
        <div>
            <h1>Game Page</h1>
            <h3>Diff: {state.difficulty}</h3>
            {reqStatus === 'isPending' && <div>Loading...</div>}
            {reqStatus === 'isError' && <div>An error occurred...</div>}
            {reqStatus === 'isSuccess' && <GameWord gameWord={gameWord} difficulty={state.difficulty}></GameWord>}
        </div>
    )
};
reactjs react-hooks
1个回答
0
投票

将自定义挂钩保留在 useEffect 之外(另请参阅挂钩规则)并从组件的根目录调用它们。然后,您可以从 useEffect 内部调用结果数据,并将数据添加到 useEffect 的依赖项数组中。如果您的唯一目的是将数据写入变量,那么您确实可以跳过 useEffect 和 useState。

由于您使用

<StrictMode>
进行调试(用于检查缺少的效果清理),API 可能会被触发两次,在这种情况下它会按预期工作。否则,这可能是由于自定义钩子的错误实现(使用重新渲染运行)引起的,但由于您只返回广泛使用和测试的钩子的结果,因此情况不应该如此。

© www.soinside.com 2019 - 2024. All rights reserved.