React:返回 JSX 的函数和函数组件有什么区别?

2023-11-22

function renderSomething(foo) {
  return <div>sth {foo}</div>
}

function Something({ foo }) {
  return <div>sth {foo}</div>
}

function Component(props) {
  const { foo } = props
  return (
    <>
        {renderSomething(foo)}
        <Something foo={foo} />
    </>
  )
}

JSX 结果为renderSomething() and <Something />是相同的。我想知道这两种方式之间有什么区别(例如渲染方式、行为、影响等)?

render 方法适用于什么场景(即renderSomething())?我可以在里面使用挂钩吗?


JSX 结果为renderSomething() and <Something />是相同的。

renderSomething(foo) and <Something foo={foo} />做完全不同的事情,但在特定的用法中,最终结果是相同的:React 创建一个 React 元素,告诉它渲染一个div稍后(如果使用该元素)。正在做renderSomething(foo)正在治疗renderSomething就像一个钩子,它会影响你在它运行时如何使用它。

以下是两个主要区别:

  1. With renderSomething(foo), your代码立即调用该函数并传入参数。和<Something foo={foo} />,你没有打电话Something。您要求 React 记住它,并在以后需要渲染您执行这些调用的组件时调用它。

  2. 因为你的代码而不是 React 调用renderSomething,如果你在其中使用了钩子,他们会将信息放入调用组件的实例和状态信息。相反,如果Something使用钩子,该实例和状态信息存储在组件实例中Something itself.

(还有其他区别。你不能使用renderSomething作为一个组件通过<renderSomething foo={foo} />因为函数组件名称必须以大写字母开头,以区别于 HTML 元素,并且因为renderSomething需要一个字符串参数,而不是 props 对象。)

让我们更仔细地看看其中的一些差异:

function renderSomething(foo) {
    console.log(`renderSomething: Called with foo = ${foo}`);
    return <div>sth {foo}</div>;
};

function Something({ foo }) {
    console.log(`Something: Called with foo prop = ${foo}`);
    return <div>sth {foo}</div>;
}

console.log(`Creating elements via renderSomething("x"):`);
const ex1 = renderSomething("x");
console.log(`Creating elements via <Something foo="x" />:`);
const ex2 = <Something foo="x" />;
console.log(`Done`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

请注意,代码called renderSomething(你看到它的console.log发生),但没有打电话Something(你看不到它的console.log)。这是因为上面的差异#1。关键是组件的函数只有在需要渲染时才会被调用。我们没有渲染上面的任何结果,因此该函数永远不会被调用。

第二个区别更微妙,但让我们假设两件事:

  1. 你的“东西”需要一个效果(也许它通过网络加载一些东西)(或者它可以是状态或引用或它使用钩子的任何其他东西),并且
  2. 使用它的组件(我们称之为Example)可能需要也可能不需要渲染它。

这很好用Something:

const { useState, useEffect } = React;

function Something({ foo }) {
    const [thing, setThing] = useState(null);
    useEffect(() => {
        setTimeout(() => {  // Fake ajax
            setThing("thing"); 
        }, 100);
    }, []);
    return <div>foo = {foo}, thing = {thing}</div>;
}

function App() {
    const [foo, setFoo] = useState("");

    return <div>
        <div>
            <label>
                <input type="checkbox" checked={!!foo} onChange={() => setFoo(foo => foo ? "" : "hi")} />
                Toggle "foo"
            </label>
            {foo ? <Something foo={foo} /> : null}
        </div>
    </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
label {
    user-select: none;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

但现在让我们尝试一下renderSomething:

const { useState, useEffect } = React;

function renderSomething(foo) {
    const [thing, setThing] = useState(null);
    useEffect(() => {
        setTimeout(() => {  // Fake ajax
            setThing("thing"); 
        }, 100);
    }, []);
    return <div>foo = {foo}, thing = {thing}</div>;
}

function App() {
    const [foo, setFoo] = useState("");

    return <div>
        <div>
            <label>
                <input type="checkbox" checked={!!foo} onChange={() => setFoo(foo => foo ? "" : "hi")} />
                Toggle "foo"
            </label>
            {foo ? renderSomething(foo) : null}
        </div>
    </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
label {
    user-select: none;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

当您勾选带有此错误的框时,它会爆炸:



Warning: React has detected a change in the order of Hooks called by App. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useState                   useState
2. undefined                  useState
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    at App (<anonymous>:35:22)
  

那是因为这使得代码调用renderSomething当我们没有在第一次渲染时调用它时。那是因为上面的#2:因为renderSomething不是组件函数,它不会获取自己的组件实例,并且对其中的钩子的任何调用就像对父组件中的钩子的调用一样(Example)。但函数组件有时不允许调用钩子,有时则不允许。那是因为React 依赖于调用 hooks 的顺序,并且该顺序必须是持续的让它进行钩子管理。再次,使用renderSomething就像那样使用renderSomething作为钩子(这正是自定义钩子的工作方式,最终调用内置钩子,然后将信息存储在父实例中)。

正如您所看到的,虽然您在示例中得到的结果是相同的,但总的来说它们是完全不同的东西。 :-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React:返回 JSX 的函数和函数组件有什么区别? 的相关文章

  • 如何使用角度在垫选择嵌套值中包含过滤器

    我正在使用带有嵌套下拉菜单的有角材料 下拉值以父级和子级为基础嵌套 我面临两个问题 自动建议不起作用 如果我输入父名称或其关联的子名称 则必须以展开模式过滤并显示特定的父视图 如果我展开第一个父视图并尝试展开第二个父视图 则第一个父视图应在
  • Google Closure 和生成的 getter/setter

    我正在尝试让 KineticJS 与 Google Closure Compiler 一起使用 然而 KineticJS 根据变量的名称生成它的 getter 和 setter 像这样的事情 add getter and setter me
  • JavaScript:所有标准内置对象实际上都是构造函数吗?

    我最近一直在研究 JavaScript 在花了几个月的时间之后 我仍然对一些内部结构感到困惑 具体来说 我试图理解所谓的标准内置对象 https developer mozilla org en US docs Web JavaScript
  • GraphQL:从对象构建查询参数

    如果我有一个对象 where publishedAt lt 2018 01 01 如何将其转换为适合查询参数的字符串 articles where publishedAt lt 2018 01 01 这看起来是一个有趣的库 我建议检查一下
  • EXT JS中有全局变量吗

    在 java 和 C 中 我们可以全局存储变量并从项目中的任何位置访问它的值 比如说 我在一个名为Residence我正在保存residenceNumber这是一个INT到一个名为的全局变量houseNumberGlobalVariable
  • 在 NodeJs 中使用 Jest 模拟 Http Post 请求

    我有一个使用本机 https request 使用 Azure Function 内的 Node Js 构建的外部 POST API 一切正常 现在我正在尝试构建单元测试用例 并对模拟 Request 方法感到震惊 回调响应具有 on 功能
  • JavaScript - babel-preset-env 不为 IE11 转换箭头函数

    我很难尝试配置 Babel 来转译 IE11 可以理解的代码 特别是箭头函数 跑步npx webpack mode development使用我的配置不会转换我的代码中的箭头函数 在eval 在生成的代码中的语句中 我可以看到所有实例都未转
  • Angularjs 使用 ng-init 为 ng-model 赋值

    您好 我有以下问题 看起来很简单并且应该有效 但事实并非如此 在我的代码中我输入了
  • pointdown 与 onclick:有什么区别?

    两者有什么区别onpointerdown and onclick事件处理程序 有任何实际差异吗 事件在 DOM 树上传播的方式不一样吗 是否有一些设备仅响应这些事件之一 我最初以为这只是pointerdown在触摸设备或笔中触发 但是onc
  • 链接index.html client.js 和 server.js

    我从 Node js 开始 我的第一个程序已经遇到了问题 下面是我正在使用的代码 索引 html
  • 多个模板槽的相同槽内容

    在vuejs中 有没有一种方法可以为多个插槽设置相同的内容 而无需复制粘贴 So this
  • 纯 JavaScript 工具提示

    我正在尝试用纯 JavaScript 制作一个工具提示 显示在hover 就像 Stack Overflow 中将鼠标悬停在个人资料名称 a 上一样div显示 我尝试使用onmouseover onmouseout并添加了setTimeou
  • jQuery 分钟和秒倒计时器

    我想创建一个 jquery 倒计时器 我尝试了以下代码 但它不起作用 我该怎么办 DEMO https jsfiddle net tbosn210 https jsfiddle net tbosn210 var interval setIn
  • CORS:为什么我的浏览器不发送 OPTIONS 预检请求?

    从我读到的内容来看CORS https en wikipedia org wiki Cross origin resource sharing 我理解它应该按如下方式工作 客户端的脚本尝试获取资源从服务器不同的起源 浏览器拦截这个请求并首先
  • Firefox 本地主机上的 Twilio 屏幕共享?

    目前 Firefox 中本地主机上的屏幕共享会引发以下错误 The request is not allowed by the user agent or the platform in the current context 这是我的代码
  • 未捕获的类型错误:无法分配给只读属性

    我正在尝试 Nicholas Zakas 所著的 Professional JavaScript for Web Developers 一书中的这个非常简单的示例 但我不知道我在这里做错了什么 我错过了一些非常简单的事情 但我被困住了 这是
  • jQuery:array[i].children() 不是函数

    以下代码的灵感来自http ignorethecode net blog 2010 04 20 footnotes http ignorethecode net blog 2010 04 20 footnotes 当您将光标移到脚注符号上时
  • 事件监听器如何/何时附加到 d3.js 中?

    我正在尝试制作一个 SVG 编辑器 长话短说 我需要将鼠标事件附加到
  • 离子选择:预选值在单击一次之前是不可见的

    我刚刚在 ionic 版本 6 中创建了一个 ion select 我的问题是 我在页面加载时已成功预选了一个值 但此预选值未显示在 UI 中 它只是在我单击选择之后出现 但在它没有出现之前 如图 2 所示 我在 ionViewWillEn
  • 将画布下载为 PNG 图像[重复]

    这个问题在这里已经有答案了 当我尝试将画布下载为 PNG 图像时 浏览器会在新页面中打开该图像 但不下载它 我的下载代码 btnScaricaEtichetta click function console log Download loc

随机推荐

  • 使用 firestore 进行多查询和分页

    我正在尝试使用 firestore 实现多查询和分页 但是一旦我将 添加到查询中 光标就不起作用 working example the doc id i save as propery on the doc ref where categ
  • 跨平台命令行脚本(例如.bat和.sh)

    我注意到 Windows 7 可以像执行 bat 文件一样执行 sh 文件 这让我想知道是否可以编写一个 sh 文件以便可以在 Windows 中执行andLinux 比如说bash 我首先想到的是编写一个 if 语句 以便 Windows
  • 建造者设计模式和工厂设计模式有什么区别? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 Builder设计模式和Factory设计模式有什么区别 哪一种更有优势 为什么 如果我想测试和比较 对比这些模式 如何将我的发现表示为图表 对于设计模式 通常没有适用于所有情况
  • Sn.exe 中自动输入密码

    我需要创建构建后事件来执行以下操作 sn i MyKey pfx MyKeyContainerName tlbimp ConfigurationName MyCom tlb out ConfigurationName NETMyCom dl
  • 我应该如何表示带有附加信息注释的 AST?

    假设我有一个用某种语言表示 AST 的简单数据类型 data Term Var String Num Integer Expr Term 实际上 它显然会有比这更多的构造函数 我可以用它来编写一个与 AST 结构匹配的简单评估函数 eval
  • 列出窗口对象的所有属性?

    我希望 动态 获取浏览器当前识别的 HTML 元素列表 例如HTMLPreElement HTMLSpanElement等等 这些对象是全局的 即 console log HTMLPreElement in window gt true 所
  • WOFF 字体,它们是什么以及我为什么要关心?

    所以 Mozilla 提出了一种新的网络字体 我不太喜欢那个世界 但我想让自己保持最新状态 那么 既然连微软都支持它 那么伟大的事情是什么 为什么我作为一个网络开发者应该关心呢 和旧的有什么区别 我们需要另一个字体系统吗 什么情况下应该使用
  • C++:宏可以将“abc”扩展为“a”、“b”、“c”吗?

    我编写了一个可变参数模板 它接受可变数量的char参数 即 template
  • 如何重写 exit(),也许通过抛出异常

    我们有一个第三方库 其编写时没有考虑多线程或异常处理 我们的主要可执行文件是多线程的并使用异常 第三方库使用exit 因严重问题 例如 驱动程序未初始化 或 文件未找到 而中止程序 呼唤exit 在多线程应用程序中是不允许的 因为它不能正确
  • 为什么“内容类型无效”

    尝试更新 Marketo 中潜在客户记录的数据字段 使用C 我发送 action updateOnly input email email protected leadQuality Hot 并返回 requestId d98e 14b2d
  • 使用 Maven 的 JUnit3 和 Junit4 XML 报告

    我试图弄清楚如何将 JUnit 3 和 4 与 Maven 结合使用假定的报告功能 但是 Google 搜索并没有太多关于如何实际运行 JUnit 通过 Maven 的信息 请获取每个测试 或所有测试 的报告及其格式 所以 我的多部分问题是
  • Google Maps API V3:如何显示从A点到B点(蓝线)的方向?

    我的数据库中有 2 个点的纬度和经度 我希望我的 Google 地图显示从 A 点到 B 点的路线 就像我们看到的那样here 谷歌地图路线 如何在地图上绘制该方向线 Use 方向服务Google 地图 API v3 它与 Directio
  • 发布时站点 DLL 似乎间歇性锁定

    我尝试通过 VS2017 中的 发布 上下文菜单将我的 net core 站点部署到 Azure 偶尔 大约三分之一的部署 我会收到以下错误 Web 部署任务失败 Web Deploy无法修改该文件 目标上的 MyCoreWebSite d
  • ios 检查 nsarray == null

    我收到了一些回复JSON 并且工作正常 但我需要检查一些null values 我找到了不同的答案 但似乎仍然不起作用 NSArray productIdList packItemDictionary objectForKey Produc
  • clearInterval 没有停止 useEffect 中的计数器

    我正在尝试使用setInterval and a clearInterval within useEffect反应钩子 计时器按预期启动 但不会停止 我正在分配setInterval to intervalID然后打电话clearInter
  • Mayavi 无法从 Spyder 中运行:抱怨“ValueError: API 'QString' ...”

    我无法从 Spyder IDE 中运行 使用 Mayavi 库 我已经在下面描述了这个问题 任何帮助都会非常有用 提前非常感谢 重现问题的步骤 只需在脚本中导入 Mayavi 库 例如使用 import mayavi mlab as mla
  • data.table R 中具有不同间隔的 findInterval()

    我很久以前就问过这个问题 但还没有找到答案 我不知道这在 stackoverflow 中是否合法 但我重新发布了它 我在 R 中有一个 data table 我想创建一个新列来查找相应年份 月份的每个价格的间隔 可重现的例子 set see
  • 提高浮点数精度[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 如何将默认浮点数精度切换为另一个精度 也许是自定义精度 我需要这个 因为我做了一些计算
  • AlertDialog.Builder 类型的 getWindow() 方法未定义

    想法取自Android 从对话框中模糊和调暗背景窗口 我无法使对话框下的内容变得模糊 调用 eula getWindow 时 我收到此错误 AlertDialog Builder 类型的 getWindow 方法未定义 eula 显示了主要
  • React:返回 JSX 的函数和函数组件有什么区别?

    function renderSomething foo return div sth foo div function Something foo return div sth foo div function Component pro