[英]How to return a function from React Hooks that need access to the state?
I'm building a custom hook to manage the data coming from a fetch/axios/promise/whateveryouwant function, this hooks allow me to update the data whenever I want using an update function that I return at the end of my hook.我正在构建一个自定义钩子来管理来自 fetch/axios/promise/whateveryouwant function 的数据,这个钩子允许我随时使用我在钩子末尾返回的更新 function 更新数据。
So for now I have two states inside my hooks:所以现在我的钩子中有两个状态:
const [data, setData] = useState<T>(defaultValue); // the data coming from the fetch, T is defined by the user of the hook
const [query, setQuery] = useState<Array<{ key: string; value: string }>>([]); // array of query option for the URL
I wanted to implement a dynamic way to add query string to the URL, so I used the query state to have an array of object representing what I wanted but I cannot access the value of the query inside of the update function when calling from outside. I wanted to implement a dynamic way to add query string to the URL, so I used the query state to have an array of object representing what I wanted but I cannot access the value of the query inside of the update function when calling from outside. Here is the hooks, I highlited the important part:
这是钩子,我强调了重要的部分:
export default function useFetchV2<T>(
defaultValue: T,
getData: (queryString?: string) => Promise<T>
): {
update: () => void;
data: T;
updateQueryValue: (key: string, value: string) => void; // update, data, updateQueryValue are the return value of the hook.
} {
const [data, setData] = useState<T>(defaultValue);
const [query, setQuery] = useState<Array<{ key: string; value: string }>>([]); // THE STATE I WANT TO ACCESS
console.log(query, data); // Here the state is updating well and everything seems fine
const update = useCallback((): void => {
let queryString;
console.log(query, data);
// But here is the problem, query and data are both at their default value. The state inside the hooks is correct but not here.
if (query.length > 0) { // query.length always at 0
queryString = _.reduce(
query,
(acc, el) => {
return `${acc}${el.key}=${el.value.toString()}`;
},
'?'
);
console.log(queryString);
}
getData(queryString).then(res => setData(res));
}, [data, getData, query]);
const updateQueryValue = useCallback(
(key: string, value: string): void => {
const index = query.findIndex(el => el.key === key);
if (index !== -1) {
if (!value) {
const toto = [...query];
_.pullAt(toto, index);
setQuery(toto);
} else {
setQuery(prev =>
prev.map(el => {
if (el.key === key) {
return { key, value };
}
return el;
})
);
}
} else {
console.log(key, value); // everything is logging well here, good key and value
setQuery([...query, { key, value }]); // setQuery correctly update the state
}
update();
},
[query, update]
);
useEffect(() => {
update();
}, []);
return { update, data, updateQueryValue };
}
It might be the way I'm exporting the function, I'm still not used to the scope.这可能是我导出function的方式,我仍然不习惯scope。
I called updateQueryValue from a component.我从一个组件中调用了 updateQueryValue。 The function is called, state is changed, but the update function can't see the difference.
调用了function,改了state,但是更新function看不出区别。
The code is calling setQuery
and then immediately calling update
and expecting query
to be updated value, but it will always be the current value of query
.代码调用
setQuery
然后立即调用update
并期望query
是更新的值,但它始终是query
的当前值。 Getting that to happen is the use case of useEffect
.实现这一点是
useEffect
的用例。
} else {
console.log(key, value); // everything is logging well here, good key and value
setQuery([...query, { key, value }]); // setQuery correctly update the state
}
// This will *always* see the current value of `query`, not the one that
// was just created in the `else` block above.
update();
update
after query
is updated, which is exactly what useEffect
is for.query
update
,这正是useEffect
的用途。const updateQueryValue = useCallback(
(key: string, value: string): void => {
const index = query.findIndex(el => el.key === key);
if (index !== -1) {
if (!value) {
const toto = [...query];
_.pullAt(toto, index);
setQuery(toto);
} else {
setQuery(prev =>
prev.map(el => {
if (el.key === key) {
return { key, value };
}
return el;
})
);
}
} else {
setQuery([...query, { key, value }]); // setQuery correctly update the state
}
// This call isn't needed, it will always "see" the old value of
// `query`
// update();
},
[query, update]
);
// Call `update` once when this custom hook is first called as well as
// whenever `query` changes.
useEffect(() => {
update();
}, [query]); // <-- this is new, add `query` as a dependency
useCallback
is only needed if something is relying on the identity of the function to make decisions; useCallback
仅在依赖 function 的身份做出决定时才需要; eg if a component receives the function as a prop, it checks whether the prop changes to decide whether to re-render.update
in this case does not need a useCallback
and might make this hook slightly harder to debug.update
不需要useCallback
并且可能会使这个钩子更难调试。function update() {
let queryString;
if (query.length > 0) { // query.length always at 0
queryString = _.reduce(
query,
(acc, el) => {
return `${acc}${el.key}=${el.value.toString()}`;
},
'?'
);
console.log(queryString);
}
getData(queryString).then(res => setData(res));
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.