gpt4 book ai didi

javascript - react Hook : what is best practice for wrapping multiple instances of a hook with a single hook?

转载 作者:行者123 更新时间:2023-12-02 22:13:51 30 4
gpt4 key购买 nike

我有一个 react 钩子(Hook)useDbReadTable,用于从接受tablenamequery初始数据的数据库读取数据。它返回一个对象,除了数据库中的数据之外,还包含 isLoading 状态。

我想将此 Hook 包装在一个新 Hook 中,该 Hook 接受 { tablename, query }数组的初始数据,并返回一个包含来自每个表的数据库,但根据我的新钩子(Hook)中的逻辑,将 isLoading 状态合并为单个 bool 值。

其想法是,新 Hook 的调用者可以从多个表中请求数据,但只需检查一个状态值。

我的想法是让新钩子(Hook)看起来像,

编辑:更新了代码(我粘贴了错误的版本)

export const useDbRead = tableReads => {
let myState = {};

for (let i = 0; i < tableReads.length; ++i) {
const { tablename, query = {} } = tableReads[i];
const [{ isLoading, isDbError, dbError, data }] = useDbReadTable(tablename, query);
myState = { ...myState, [tablename]: { isLoading, isDbError, dbError, data }};
}

const finalState = {
...myState,
isLoading: Object.values(myState).reduce((acc, t) => acc || t.isLoading, false),
};

return [finalState];
};

但是,eslint 在我的 useDbReadTable 调用中给出了这个错误:

React Hook "useDbReadTable" may be executed more than once. Possibly because it is called in a loop. React Hooks must be called in the exact same order in every component render. react-hooks/rules-of-hooks

Rules for Hooks说,

Only Call Hooks at the Top Level

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in depth below.)

阅读规则和解释后,似乎唯一的问题是确保在所有重新渲染时以相同的顺序调用钩子(Hook)。只要我确保传递给新钩子(Hook)的表列表永远不会改变,我的新钩子(Hook)不应该正常工作吗(正如我的初始测试所示)?或者我错过了什么?

更重要的是,是否有更好的想法如何实现这一点,并且不违反 Hooks 规则?

编辑2:如果它有帮助,这里是useDbReadTable。请注意,它包含的功能比我在问题中提到的更多,因为我想让问题尽可能简单。我的问题是我的 useDbRead 是否是一个好的解决方案,或者是否有一个好的方法可以在不违反 Hooks 规则的情况下做到这一点?

export const useDbReadTable = (initialTableName, initialQuery = {}, initialData = []) => {
const dbChangeFlag = useSelector(({appState}) => appState.dbChangeFlag);
const [tableName, setTableName] = useState(initialTableName);
const [query, setQuery] = useState(initialQuery);
const [state, dispatch] = useReducer(dataFetchReducer, {
isLoading: false,
isDbError: false,
dbError: {},
data: initialData,
});
useEffect(() => {
let didCancel = false;

const fetchData = async () => {
dispatch({ type: dataFetch.FETCH_INIT });

try {

const result = Array.isArray(query) ?
await db[tableName].batchGet(query) // query is an array of Ids
:
await db[tableName].find(query);

if (!didCancel) {
dispatch({ type: dataFetch.FETCH_SUCCESS, payload: result });
}
} catch (error) {
if (!didCancel) {
dispatch({ type: dataFetch.FETCH_FAILURE, payload: error });
}
}
};

fetchData().then(); // .then() gets rid of eslint warning

return () => {
didCancel = true;
};
}, [query, tableName, dbChangeFlag]);

return [state, setQuery, setTableName];
};

最佳答案

您可以通过使 useDbRead 本身数组感知来避免使用 useDbReadSingle。像这样的东西:

export const useDbRead = tableReads => {
const [loading, setLoading] = useState(true);

useEffect(() => {
const doIt = async () => {
// you would also need to handle the error case, but you get the idea
const data = await Promise.all(
tableReads.map(tr => {
return mydbfn(tr);
})
);

setLoading(false);
};

doIt();
}, [tableReads]);

return { loading, data };
};

当您需要使用它来读取单个表时,只需使用具有单个元素的数组来调用它即可。

const {loading, data: [d]} = useDbRead([mytableread])

关于javascript - react Hook : what is best practice for wrapping multiple instances of a hook with a single hook?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59460331/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com