简化 react hook 的方法?

2022-09-15 23:37:02 +08:00
 RRRSSS

我的场景是这样的:

  1. API a 是比较常见的接口,几乎每个页面都要调用
  2. API b 是依赖 a 的结果,去调用的

我先把 API a 和 b 用 react query 抽象成 hook:

const useFetchA = (params) => {
	return useQuery(['fetchA', params], async () => {
    	return await API.a(params)
    })
}

// useFetchB 也类似,就不写了

然后在很多组件上都有这样的两行:

const resA = useFetchA('xxx');
const resB = useFetchB('yyy');

我也想过要 API.a 和 API.b 放在一个 hook 里,但是这样,单独使用 API.a 或 API.b 的时候就不方便了。

也想过把 useFetchA 和 useFetchB 再放在一个 hook 里,类似这样:

const useFetchAandB = (params) => {
	const {data: resA} = useFetchA(params)
    const {data: resB} = useFetchB(resA)
}

不知道这样是否可行?有什么隐患?是否符合规范?

2595 次点击
所在节点    React
14 条回复
codehz
2022-09-15 23:41:25 +08:00
react query 不是自带缓存管理的吗(
重复写又不会重复请求
tonytonychopper
2022-09-15 23:56:19 +08:00
我理解 hook 就是可以随便组合的,只要逻辑清晰就行了
RRRSSS
2022-09-16 00:09:58 +08:00
@codehz 好吧,可能我例子特殊了,如果不用 react query 呢?只是 axios 请求呢?

我只是想用这个例子,看看这种情况怎么样比较合适?
codehz
2022-09-16 00:12:04 +08:00
@RRRSSS 这就是为啥不应该用 useEffect 来做这种操作(
https://blog.skk.moe/post/why-you-should-not-fetch-data-directly-in-use-effect/
changwei
2022-09-16 00:32:41 +08:00
用 swr ,把前一个 swr 请求的返回结果作为下一个 swr 的 key 即可,不用担心缓存问题,swr 会自动帮你解决
RRRSSS
2022-09-16 00:41:20 +08:00
@changwei emm..

我换个例子吧,不是请求,只是一个副作用,比如第一个 hook 是改 title ,第二个 hook 是根据这个 title 是否是 'homepage' 而去 useWindowSize 。好吧,我没编出来。就是这个意思,怎么弄呢、
RRRSSS
2022-09-16 00:43:21 +08:00
@codehz @tonytonychopper 关键是如果想要这种就不行了,不能放在 if 里:

```js
const useFetchAandB = (params) => {
const {data: resA} = useFetchA(params)
if (resA === 'foo') {
const {data: resB} = useFetchB(resA)
}
}
```

这样就不能抽象成 hook 了吧
Pastsong
2022-09-16 00:51:31 +08:00
useFetchAandB
useFetchA
useFetchB
同时存在,想用啥用啥
codehz
2022-09-16 00:54:32 +08:00
@RRRSSS useSWR key 为 null 的时候不会发出请求,完美符合需求
CptDoraemon
2022-09-16 02:18:30 +08:00
@RRRSSS
```js
const useFetchAandB = (params) => {
const {data: resA} = useFetchA(params);
const {data: resB, doFetchB} = useFetchB();
const previousResARef = useRef(resA);

useEffect(() => {
if (previousResARef.current !== 'foo' && resA === 'foo') {
}
})
```
CptDoraemon
2022-09-16 02:20:00 +08:00
tab 到回复了 lol

```js
const useFetchAandB = (params) => {
const {data: resA} = useFetchA(params);
const {data: resB, doFetchB} = useFetchB();
const previousResARef = useRef(resA);

useEffect(() => {
if (previousResARef.current !== 'foo' && resA === 'foo') {
doFetchB(resA)
}
})
```
codehz
2022-09-16 10:29:32 +08:00
(再动态一点可以考虑包一层组件,虽然 hook 不能写条件,但是组件可以随便加
做类似无限滚动的话还可以用 useSWRInfinite
jjwjiang
2022-09-16 11:17:11 +08:00
B 既然依赖 A 的结果,那你定义 useFetchB 的时候给个入参就行了,这样所有用到 fetchB 的地方就必须传入 A 的结果

如果 A 的查询和每个页面内容无关,那直接把 A 写到 useFetchB 里面去
tonytonychopper
2022-09-17 00:36:31 +08:00
@RRRSSS #7 这样写本来就会有坑,如果一定要这么写的话,不如在 useFetchB 内部做判断:

function useFetchB
if resA === 'foo' then do something

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/880396

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX