React的useRequest()钩子,再次审视run参数传递的问题
发布于 作者:苏南大叔 来源:程序如此灵动~useRequest()
的官方文档里面,给出的demo
,都没有对网络请求使用参数的问题,进行很好的处理和说明。唯一相关的线索就是有个参数叫做defaultParams
。这里的文档对新手还是挺不友好的。苏南大叔就useRequest()
执行的请求,使用参数的问题,做个简单的总结。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。文章的原理,以前的文章里面都说过。这里就是一篇总结性的文章。
前文回顾
本文不涉及proxy
的问题,也不涉及express
接收参数的问题。和本文最相关的文章,有以下几篇:
- https://newsn.net/say/react-userequest.html
- https://newsn.net/say/react-proxy-2.html
- https://newsn.net/say/js-bind.html
总体上来说,如果对本文产生迷惑的话,就是语法的问题。集中表现在导出函数函数run
身上,它代表了将要被执行的fetchData
,并且没有传递任何参数。
const { run }= useRequest( fetchData );
起点,fetchData
先说这个事情的宇宙原点fetchData
,注意这里写法上就是个函数定义,并不是个带()
的函数执行。如果对其再进行包装的话,可以是这样的:
fetchData
() => fetchData()
() => {return fetchData();}
,注意这里的return
字样,非常重要。(...args) => fetchData(...args)
这里,其实主要考察的是匿名函数的写法,所以,不明白的可以参考下面的这篇文章:
原始状态,没实际使用的参数
如果这个时候,如果fetchData
内的逻辑,不真正使用参数的话,上面的写法就全部合格没有问题。也可以在代码体中,使用run
字样来激活上述代码中fetchData
。例如:
const { run } = useRequest( fetchData );
<button onClick={run}>请求</button>
日常状态,使用参数逻辑
情况有变,fetchData
需要接收并使用一个参数url
,这个时候必须保证这个url
参数逻辑。例如:
function fetchData(url) {
console.log(url);
if (url === undefined) {
// 首次刷新,并且没有设置defaultParams
alert("参数缺失");
return;
} else if (typeof url != "string") {
// 单独执行`run`,参数传递错误。
alert("参数类型错误");
return;
}
// run.bind({},url)
return fetch(url).then((response) => {
return response.json();
});
}
这个情况下,参数的获取和执行,就非常重要了。
修改点一
可以凸显url
参数的存在,或者不凸显。(并不重要,不修改也可以,或者改成其它也行)
const { data, run } = useRequest(fetchData);
或者
const { data, run } = useRequest((url)=>fetchData(url));
或者
const { data, run } = useRequest((...args)=>fetchData(...args));
修改点二【重点】
如果还使用官方推荐的写法({run}
)的话,接收到的url
是个[object object]
,所以是错误的调用。例如:
<button onClick={run}>请求</button>
正确的写法,是写个.bind()
的形式。(在react
项目里面,很常见的)
<button onClick={run.bind({},"/api/url")}>正确写法请求</button>
<button onClick={()=>run("/api/url")}>正确写法请求2</button>
这样写的话,就能正确接收到参数url
。
修改点三【重点】
对于useRequest()
这个钩子来说,它有个默认组件加载完就自动执行的选项(manual: false
)。这种情况下,按照官方文档的写法,拿到的url
就是个undefined
。
解决方案是:再增加个新的选项defaultParams:[]
。
defaultParams
是个被动效果。在自动执行的时候,传递个默认的参数进去。和单独使用的run
没有关系。run
是个主动效果。在人为触发run
的时候,默认情况下是没有明面上传递参数的。实际上潜藏的传递了个object
作为第一个参数。然后误打误撞,称为了url
参数。
苏南大叔这边理解着,defaultParams
就是和...args
的args
是一样的效果,是个参数集合。
const { data, run } = useRequest( fetchData,{
defaultParams:['/api/default']
});
const { data, run } = useRequest( (url)=>fetchData(url),{
defaultParams:['/api/default']
});
测试代码
App.js
:
import React from "react";
import { useRequest } from "ahooks";
function fetchData(url) {
console.log(url);
if (url === undefined) {
// 首次刷新,并且没有设置defaultParams
alert("参数缺失");
return;
} else if (typeof url != "string") {
// 单独执行`run`,参数传递错误。
alert("参数类型错误");
return;
}
// run.bind({},url)
return fetch(url).then((response) => {
return response.json();
});
}
function App() {
const { data, run, refresh } = useRequest(fetchData, {
defaultParams: ["/api/defaultParams"],
// refresh和这个参数无关,机器重复上一次请求,上一次错误这次还错误,上一次正确这次还正确。
});
return (
<div>
<h3>有参数的时候,需要更换run的写法,使用 .bind()</h3>
1、首次刷新自动执行的时候,需要使用defaultParams
<br />
<button onClick={run}>2、正确写法变错误,object</button>
<br />
<button onClick={run.bind({}, "/api/run")}>3、正确写法,bind</button>
<br />
<button onClick={() => run("/api/run2")}>4、正确写法2,匿名函数</button>
<br />
<button onClick={refresh}>5、refresh,无关对错</button>
<br />
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default App;
src/setupProxy.js
:
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
createProxyMiddleware("/api", {
target: "http://localhost:3222",
changeOrigin: true,
pathRewrite: {
"^/api/": "",
},
})
);
};
express.js
:
const express = require("express");
const app = express();
var cors = require("cors");
app.use(cors());
app.all("*", (req, res) => {
ret = {
host: req.headers.host,
url: req.url,
time: Date.now().toString().slice(-6),
};
res.send(JSON.stringify(ret));
});
const server = app.listen(process.env.PORT || 3222, () => {
const port = server.address().port;
console.log("http://localhost:%d", port);
});
useRequest的更多写法
还是useRequest()
这个钩子的最基本的使用,核心代码:
const { data, run } = useRequest(fetchData);
const { data, run } = useRequest(()=>fetchData());
const { data, run } = useRequest(()=>{fetchData()}); //错误的写法,丢了`return`
const { data, run } = useRequest(()=>{return fetchData()});
const { data, run } = useRequest((url)=>fetchData(url));
const fetchDataBefore = function(url){
return fetchData(url);
}
const { data, run } = useRequest(fetchDataBefore);
run的更多写法
单纯的run
,不能判断是否正确的写法。和是否有参数需求有关。
<button onClick={run}>运行</button>
<button onClick={run.bind({},"/link2")}>运行</button>
<button onClick={()=>run()}>运行</button>
<button onClick={()=>run("/api/run")}>运行</button>
题外话,refresh
在userequest
官方文档里面,除了run
(runasync
)外,还有另外一个refresh
导出函数。它和参数是否传递没有关系。因为它的主要作用就是重复上一条请求。那么,它无关对错,无关参数。
const { data, run, refresh } = useRequest(fetchData, {
defaultParams: ["/api/defaultParams"],
// refresh和这个参数无关,机器重复上一次请求,上一次错误这次还错误,上一次正确这次还正确。
});
<button onClick={refresh}>refresh,无关对错</button>
结语
更多react
经验文章总结,参考苏南大叔的博客:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。