我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

useRequest()的官方文档里面,给出的demo,都没有对网络请求使用参数的问题,进行很好的处理和说明。唯一相关的线索就是有个参数叫做defaultParams。这里的文档对新手还是挺不友好的。苏南大叔就useRequest()执行的请求,使用参数的问题,做个简单的总结。

苏南大叔:React的useRequest()钩子,再次审视run参数传递的问题 - run参数传递
React的useRequest()钩子,再次审视run参数传递的问题(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1。文章的原理,以前的文章里面都说过。这里就是一篇总结性的文章。

前文回顾

本文不涉及proxy的问题,也不涉及express接收参数的问题。和本文最相关的文章,有以下几篇:

总体上来说,如果对本文产生迷惑的话,就是语法的问题。集中表现在导出函数函数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就是和...argsargs是一样的效果,是个参数集合。
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;

苏南大叔:React的useRequest()钩子,再次审视run参数传递的问题 - 测试代码
React的useRequest()钩子,再次审视run参数传递的问题(图3-2)

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>

苏南大叔:React的useRequest()钩子,再次审视run参数传递的问题 - bind参数代码
React的useRequest()钩子,再次审视run参数传递的问题(图3-3)

题外话,refresh

userequest官方文档里面,除了runrunasync)外,还有另外一个refresh导出函数。它和参数是否传递没有关系。因为它的主要作用就是重复上一条请求。那么,它无关对错,无关参数。

const { data, run, refresh } = useRequest(fetchData, {
    defaultParams: ["/api/defaultParams"],
    // refresh和这个参数无关,机器重复上一次请求,上一次错误这次还错误,上一次正确这次还正确。
});
<button onClick={refresh}>refresh,无关对错</button>

结语

更多react经验文章总结,参考苏南大叔的博客:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react