React: React Fire:现代化 React DOM

创建于 2018-08-31  ·  227评论  ·  资料来源: facebook/react


有关最新状态,请参阅 2019 年 6 月 5 日的更新: https ://github.com/facebook/react/issues/13525#issuecomment -499196939


今年,React 团队主要专注于对 React 的基本改进

随着这项工作越来越接近完成,我们开始考虑 React DOM 的下一个主要版本应该是什么样子。 有很多已知问题,如果没有更大的内部更改,其中一些是很难或不可能解决的。

我们希望消除过去导致无数后续修复并造成大量技术债务的错误。 我们还想删除事件系统中的一些抽象,这些抽象从 React 的第一天开始就几乎没有受到影响,并且是很多复杂性和包大小的来源。

我们称这项工作为“React Fire”。

🔥 反应火

React Fire是对 React DOM 进行现代化改造的努力。 我们的目标是让 React 更好地与 DOM 的工作方式保持一致,重新审视一些有争议的过去导致问题的决定,并使 React 更小更快。

我们希望在未来的 React 主要版本中发布这组更改,因为不幸的是其中一些会被破坏。 尽管如此,我们认为它们是值得的。 我们在 Facebook 拥有超过 50,000 个组件,以确保我们对迁移策略保持诚实。 除了一些有针对性的修复或自动代码模块之外,我们无法重写产品代码。

战略

有几个不同的东西构成了我们目前的计划。 我们可能会添加或删除一些东西,但到目前为止的想法是:

  • 停止在value属性 (https://github.com/facebook/react/issues/11896) 中反映输入值。 这最初是通过https://github.com/facebook/react/pull/6406 在 React 15.2.0 中添加的。 这是非常普遍的要求,因为人们对 DOM 的概念模型是他们在 DOM 检查器中看到的value应该匹配value JSX 属性。 但这不是 DOM 的工作方式。 当您输入字段时,浏览器不会更新value属性。 React 也不应该这样做。 事实证明,这种变化虽然可能对一些依赖 CSS 选择器的代码有所帮助,但会导致一连串的错误——其中一些直到今天仍未修复。 此更改的一些后果包括: https ://github.com/facebook/react/issues/7179、https://github.com/facebook/react/issues/8395、https : //github.com/facebook /react/issues/7328 , https://github.com/facebook/react/issues/7233 , https://github.com/facebook/react/issues/11881 , https://github.com/facebook/react /issues/7253,https://github.com/facebook/react/pull/9584,https://github.com/facebook/react/pull/9806,https://github.com/facebook/react/pull _ _ _ /9714,https://github.com/facebook/react/pull/11534,https://github.com/facebook/react/pull/11746,https://github.com/facebook/react/pull/12925 _ _ _ . 在这一点上,继续与浏览器抗争显然是不值得的,我们应该恢复它。 这段旅程的积极部分是,由于我们的 DOM 贡献者(@ nhunzaker 、@ aweary 、@ jquense和 @philipp-spiess)的不懈努力,我们现在有了详细的 DOM 测试装置,可以帮助我们避免回归。

  • 在 React 根目录而不是文档中附加事件 (https://github.com/facebook/react/issues/2043)。 将 React 应用程序嵌入到更大的系统中时,将事件处理程序附加到文档成为一个问题。 Atom 编辑器是最早遇到此问题的案例之一。 任何大型网站最终也会开发出与stopPropagation与非 React 代码或跨 React 根交互相关的非常复杂的边缘案例(https://github.com/facebook/react/issues/8693、https://github .com/facebook/react/pull/8117,https://github.com/facebook/react/issues/12518)。 我们还希望将事件急切地附加到每个根,以便我们可以在更新期间进行更少的运行时检查。

  • onChange迁移到onInput并且不要为不受控制的组件填充它(https://github.com/facebook/react/issues/9657)。 有关详细计划,请参阅链接问题。 令人困惑的是,React 对 DOM 中的input事件使用了不同的事件名称。 虽然我们通常会避免在没有显着好处的情况下进行这样的大更改,但在这种情况下,我们希望更改行为以消除一些仅在改变受控输入等边缘情况下才需要的复杂性。 因此,将这两个更改一起进行是有意义的,并以此为契机使onInputonChange完全按照 DOM 事件对不受控制的组件所做的工作。

  • 大大简化事件系统(https://github.com/facebook/react/issues/4751)。 当前的事件系统自 2013 年首次实现以来几乎没有改变。它在 React DOM 和 React Native 中被重用,因此它是不必要的抽象。 它提供的许多 polyfills 对于现代浏览器来说是不必要的,其中一些产生的问题比它们解决的问题还要多。 它还占 React DOM 包大小的很大一部分。 我们在这里没有一个非常具体的计划,但我们可能会完全分叉事件系统,然后看看如果我们更接近 DOM 给我们的东西,我们能做到什么程度。 我们将完全摆脱合成事件是合理的。 我们应该停止冒泡事件,例如在 DOM 中不会冒泡且没有充分理由冒泡的媒体事件。 我们希望保留一些特定于 React 的功能,例如通过门户冒泡,但我们将尝试通过更简单的方式来做到这一点(例如重新调度事件)。 被动事件可能是其中的一部分。

  • classNameclass (https://github.com/facebook/react/issues/4331,另见https://github.com/facebook/react/issues/13525#issuecomment- 417818906 下面)。 这已被无数次提出。 我们已经允许在 React 16 中将class向下传递到 DOM 节点。这造成的混乱不值得它试图防止的语法限制。 我们不会单独进行此更改,但将其与上面的所有其他内容结合起来是有意义的。 请注意,我们不能在没有警告的情况下只允许两者,因为这使得组件生态系统很难处理。 每个组件都需要学习正确处理两者,并且存在冲突的风险。 由于许多组件处理className (例如通过附加到它),它太容易出错。

权衡取舍

  • 如果我们的目标是继续为 React Native Web 等项目公开当前私有的 React 事件系统 API,我们就无法进行其中的一些更改。 然而,React Native Web 将需要一个不同的策略,因为React Fabric可能会将更多的响应系统移动到本机端。

  • 我们可能需要放弃与一些旧版浏览器的兼容性,和/或需要更多独立的 polyfills。 我们仍然关心支持 IE11,但我们可能不会尝试消除一些现有的浏览器差异——这是许多现代 UI 库所采取的立场。

推出计划

在这个阶段,该项目非常具有探索性。 我们不确定上述所有事情是否会成功。 因为这些变化很重要,我们需要在 Facebook 上进行测试,并逐步进行尝试。 这意味着我们将引入一个功能标志,分叉一些代码,并在 Facebook 上为一小部分人启用它。 开源 16.x 版本将保留旧行为,但在 master 上,您将能够在打开功能标志的情况下运行它。

我计划大部分时间自己从事这个项目,但我非常感谢@ nhunzaker 、@ aweary 、@ jquense和@philipp-spiess 的更多讨论和贡献,他们一直是出色的合作者,并且在很大程度上指导了 React DOM我们正在研究光纤。 如果您对某些领域特别感兴趣,请告诉我,我们会解决的。

我可能在这个计划中错过了一些事情。 我非常愿意接受反馈,希望这篇文章对您有所帮助。

DOM React Core Team Big Picture

最有用的评论

除了className变化之外,我喜欢这些点中的每一点。 这似乎与其他观点追求的目标完全矛盾(与 DOM API 保持一致)。 React 绑定到 DOM 属性,而不是 HTML 属性(这甚至在第一点中阐明)。 DOM Element 属性被命名为className ,而不是class 。 那么为什么在 React 中它会被命名为class呢?

所有227条评论

我喜欢这个。 减少捆绑包大小和“类”属性是非常受欢迎的更改。

做得好!

🙂

注意表单库作者! 🤣

伟大的!

className → 班级很棒

其他人呢? 仍然在做clipPathhtmlFortabIndex等似乎很奇怪。

采用class是使库对初学者更友好的重大突破。 恭喜。

这太棒了。 我很好奇转移到class是如何与道具一起工作的。

似乎({ class }) => <div class={class} />最初会出现保留关键字问题?

这是个好消息,谢谢@gaearon!

除了className变化之外,我喜欢这些点中的每一点。 这似乎与其他观点追求的目标完全矛盾(与 DOM API 保持一致)。 React 绑定到 DOM 属性,而不是 HTML 属性(这甚至在第一点中阐明)。 DOM Element 属性被命名为className ,而不是class 。 那么为什么在 React 中它会被命名为class呢?

极好的! 您有减少捆绑包大小的目标吗?

👏

其他人呢? 仍然在做 clipPath、htmlFor、tabIndex 等似乎很奇怪。

我愿意讨论,但我认为这些更改不值得(也许for除外)。

我认为重写事件系统是其中最有趣的方面。 有很大的机会可以减少捆绑包的大小并简化社区贡献。

我们开始做吧!

我想知道同时发布JSX 2.0是否值得? 无论如何,人们将需要重新学习一些东西。 也许一次重新学习一堆东西比在一段时间内两次学习一些东西更好? 只是我读到这里时的一个想法。

我喜欢这些点中的每一点,除了 className 的变化。 这似乎与其他观点追求的目标完全矛盾(与 DOM API 保持一致)。 React 绑定到 DOM 属性,而不是 HTML 属性(这甚至在第一点中阐明)。

然而,如果我们传递一个未知的键/值对,它将被视为自 React 16 以来的属性。所以我们已经不一致了。 另外,我的评论是关于用户错误地期望 React设置value属性。 React API 在API 中使用属性名称还是属性名称是完全正交的。

多年来,我一直为你的这一论点辩护,但我现在认为这是不值得的摩擦。 你不会从中得到任何好处。 只是让人们使用class并没有负面影响,除了它不适用于解构和迁移成本。 每个人在学习 React 时都会抱怨它。 我认为在这种情况下做人们期望的事情比迂腐更重要。 既然我们无论如何都要改变其他 DOM 的东西,让我们一起批处理。

只要 React Fire 燃烧得很快.... 👍

这些变化都很棒。 我对此及其对react-testing-library的影响感到非常兴奋。 特别是,绑定到 react 根的事件(或者甚至可能完全放弃事件委托,因为在现代环境中可能不再需要它?),可能会删除/重写合成事件,以及onChange -> onInput将认真改进react-testing-library的实现和使用该工具的体验。

我很乐意提供反馈,因为它正在实施。

甚至可能完全放弃事件委托,因为在现代环境中可能不再需要它了

我们考虑了这一点,但认为这可能过于简单化了。 事件委托让我们避免在初始渲染时为每个节点设置一堆监听器。 并在更新时交换它们。 这些方面不应该被忽视。 不过,可能还有更多的基准测试要做。

@tannerlinsley ({ class: className }) => <div class={className} />不幸的是,这将杀死 jsx 2.0 对象简写符号( <div class /> ),但就这样吧......

如果class最终可以将对象和数组放在字符串旁边,那就太好了。

您有减少捆绑包大小的目标吗?

删除三分之一的 React DOM 会很好。 走着瞧。 很难说早,但我们会尽力而为。

哇,当人们问我关于 React 的缺点时,我提到的几乎所有设计决策都列举了。

喜欢这个方向。

对于使用className并希望支持多个 React 版本的库,升级路径是什么?

@gaearon也许这没什么大不了的,今天很高兴说“道具是 DOM 属性而不是 HTML 属性”,现在它将是“除了 className,那个是 HTML 名称”。 我还希望能够复制/粘贴 SVG,而无需 10 分钟的时间弄乱属性以与 React 匹配

htmlFor呢?

感觉className -> class转换必须非常小心地完成,可能需要很长一段时间。 这会给生态系统带来很多问题,因为几乎每个组件都需要更改——即使是非常微不足道的组件。 如果您“拥有”代码并且有一个 codemod,这通常很好,但是当您依赖 3rd 方库时,您在很大程度上受维护者的摆布。

从生态系统的角度来看,其余的变化似乎风险相对较低,但摆脱className确实会带来很多痛苦。 似乎应该可以将其拆分为一个单独的问题,并以与其余 🔥 更改不同的时间表发布。

我同意@felixfbecker
一切听起来都很棒,并且可以提高开发人员和用户的质量,但是 className 发生了变化。

Beeing 能够解构所有属性,但一个肯定会导致更多的混乱,并且比他们需要使用 className 更难向新用户解释,因为 class 是一个关键字(他们可以清楚地看到错误何时发生,因为它的颜色不同) . 在解构中解决类需要引入新语法或完全不同的方式来读取特定属性,该特定属性只有在您需要使用休息属性时才会起作用。
仅仅为了保存四个字符就会产生很多问题。

@felixfbecker可能是class / for在 JSX 和className / htmlFor在 JS 版本?

<label class="foo" for="bar">..</label>

将是

React.createElement('label', {className: 'foo', htmlFor: 'bar'}, '..')

伟大的计划! 很高兴来到这里! 👏👏👏

这太棒了,我迫不及待地想研究新的东西。

大大简化事件系统 (#4751)。

现在 react 不能将处理程序委托给自定义元素,而不扩展 ReactDOM 定义。 https://github.com/facebook/react/issues/9242

这意味着 React 不能在自定义元素上设置自定义处理程序,例如<x-component onMyEvent={ev => {...}} />

@gaearon
你对此有什么计划吗?

所有这些变化都非常好,但在我看来,最大的元变化是尺寸减小。 React 有一个平均 DX,但它足够胖以至于在普通网络上下载和解析它是一个问题,特别是在移动设备上。

我们可以拥有一切!

重写事件委托会为修复#1254打开大门; 其中一些事件会降低它们所连接的节点的性能(对于 React 来说,这意味着整个应用程序)。

另外,从长远来看,您是否考虑过使用合成数据集道具? 在将 props 转发到 DOM 节点时,无法键入允许的 HTML 道具(因为 data-*)会导致大量错误。 当前类型化的 React 组件必须在 props 的确切类型和允许的数据属性之间进行选择。

我很兴奋

@ryanflorence有点离题,但令人遗憾的是,没有人(据我所知)有想法制作一个 html/css/svg -> jsx 转换器,以便通过对映射 HTML 进行如此多微不足道的更改来简化向 React 的迁移属性到 React 道具。 这么多工时浪费在执行主要是查找和替换:(

在同一个问题(和评论)中看到以下内容很奇怪:

我们的目标是让 React 更好地与 DOM 的工作方式保持一致
类名→类
仍然在做 clipPath、htmlFor、tabIndex 等似乎很奇怪。

当所有这些都是 DOM API 的直接对应物时

而且这个论点没有通过:

多年来,我一直为你的这一论点辩护,但我现在认为这是不值得的摩擦。 你不会从中得到任何好处。 只是让人们使用类没有任何负面影响,除了它

React 一直只是 JS 之上的一个非常薄的层。 所以除了 JSX 的尖括号之外的所有东西都是 JS _并且_在 DOM API 中有直接对应的与 DOM 直接相关的东西: classNameclipPathhtmlFortabIndex等等等等。

随着引入class的决定,React 不再是一个薄层( class是 JS 中的保留字),并脱离了与 DOM API 更兼容的声明目标。

看到你想要“从 onChange 迁移到 onInput”尤其令人不安,因为它与 DOM 不一致_并且_通过迁移className -> class变得与 DOM 不一致。

此外,这会带来一大堆蠕虫,因为人们会要求(并且已经要求)对其他部分进行更改。 只是在评论中:为什么我们使用dataset而不是data-* ? 也许是因为data-*不是有效的 JS(很像class )并且因为它与DOM API一致? 为什么我们不改变htmlFor ? 因为for是保留字,而htmlFor在 DOM API 中? 等等等等等等

然而,如果我们传递一个未知的键/值对,它将被视为自 React 16 以来的属性。所以我们已经不一致了。

@gaearon这也是为什么 React 是唯一在 CustomElements Everywhere 互操作测试中得分不佳的库的原因: https ://custom-elements-everywhere.com/
并且有很多问题要求更改它: https://github.com/facebook/react/issues/11347https://github.com/facebook/react/issues/7249https://github.com/facebook /反应/问题/9230

这可能不是问题,但是 React Fire 与 React Fiber 的相似性会让非英语母语人士感到困惑吗? 我经常认为纽瓦克宾州车站和纽约宾州车站在纽约市的同一条火车线上对游客来说是一个特别残酷的笑话。

如果这是一个真正的问题,您可以将其称为 React Flame 并且仍然保持火焰 🔥 表情符号。

重写事件委托会为修复#1254打开大门; 其中一些事件会降低它们所连接的节点的性能(对于 React 来说,这意味着整个应用程序)。

以某种形式修复 #1254 绝对是我希望看到的。

另外,从长远来看,您是否考虑过使用合成数据集道具?

我现在不想承诺这样的事情,因为有更大的表面。 更丰富的 DOM 接口( ariaSetdataSetclassList )是有道理的,但目前尚不清楚我们想在 React DOM 中投入多少,而不是一个更高级别的库为您提供更丰富的 DOM API。 由于这些变化更具装饰性但具有较高的表面积,我会暂缓使用它们。

反应炽热🔥

@ryanflorence有点离题,但令人遗憾的是,没有人(据我所知)有想法制作一个 html/css/svg -> jsx 转换器,以便通过对映射 HTML 进行如此多微不足道的更改来简化向 React 的迁移属性到 React 道具。 这么多工时浪费在执行主要是查找和替换:(

@jxub
https://transform.now.sh/html-to-jsx/

对新变化感到非常兴奋,你们这些来自 Facebook 的人类正在通过这次迁移创造历史。 50k 组件将迁移到 React Fire 吗?
您的测试套件必须非常紧凑 <3

React Fire 与 React Fiber 的相似性会让非英语母语人士感到困惑吗?

也许也适用于听障人士(或其他有影响单词歧视的条件的人)

感谢分享@gaearon ,太棒了!

我希望看到 JSX 2.0 版本解决了我们使用 Babel 和 Typescript 编译代码时出现的空白和换行问题。

有不同的问题打开了,我试图贡献,但被告知,因为 React 团队需要审查 JSX 周围的所有内容。

这个问题无论如何都与 dom 有关,因为我们将 jsx 转换为 js 的方式不允许 w3c 所说的内容。

这是问题https://github.com/facebook/jsx/issues/19

我的评论在最后。

我认为, className没问题。 让它成为它的样子。 不要雪上加霜。

有人可以澄清这如何影响现有的处理程序吗?

停止在 value 属性中反映输入值

React 是否仍会在处理程序中使用准确的event.target.value更新来控制输入,或者这是否只会影响从 refs 和 DOM 节点读取值?

@nickmccurdy它会影响您在浏览器开发工具中看到的内容

@tomdale React Ember 🔥

好的! 我正在等待查看 React 17 的完整更改列表。
我相信这将是 ReactJS 的新时代。 🔥⚛️

@tomdale嗯:纱线、纤维、织物; 也许可以使用另一个与服装相关的术语? 😆

然而,如果我们传递一个未知的键/值对,它将被视为自 React 16 以来的属性。所以我们已经不一致了。

@gaearon这也是为什么 React 是唯一在 CustomElements Everywhere 互操作测试中得分不佳的库的原因: https ://custom-elements-everywhere.com/

不,这不是原因(自​​定义元素和普通元素是完全独立的代码路径)。 原因是我们已经有了旧的行为并且不想破坏向后兼容,除非新的行为是可靠的。 我认为解决更好的自定义元素互操作作为这个保护伞的一部分有意义的。

React Fire 与 React Fiber 的相似性会让非英语母语人士感到困惑吗?

两者都是内部代号,一旦项目完成就没有任何意义。 React Fire 只是为了让 React DOM 变得更好——当它成为生产就绪的时候,它将只是 React DOM。

React 是否仍会在处理程序中使用准确的 event.target.value 更新来控制输入,或者这是否只会影响从 refs 和 DOM 节点读取值?

是的,因为event.target.value是一个属性。 我们正在讨论停止更新属性。 其他流行的图书馆都没有这样做(AFAIK),这会导致无数问题。 它不应该影响您的代码,除非您在值上依赖 CSS 选择器(无论如何这可能很糟糕)。

好的! 我正在等待查看 React 17 的完整更改列表。

请注意,我们不承诺在 17 岁之前准备好。可能是 18 岁。或 19 岁。😅

很高兴看到像 React 这样好的库在稳步发展。 🎉 class将使可用性更好,imo值得

@gaearon

自定义元素和普通元素是完全独立的代码路径

这本身似乎也需要解决。 有什么理由不把所有元素都一视同仁吗? 这就是 HTML 和 DOM 规范的意图。

@justinfagnani如前所述,我们当时没有这样做的原因是因为没有关于如何判断是设置属性还是属性的约定 - 并且存在使用检查的风险,我们有风险进行检查Web 平台不可能为原型添加新属性。 我认为到目前为止, @robdodson一直在研究的 RFC 和 PR 中已经达成了某种共识,我们可能可以从那里得到它。

👍 🔥 🔥 🔥

React Fire 还应该允许我们应用 Inferno 拥有的一些巧妙的性能优化——但由于重大更改而无法应用。 激动人心的时刻:)

LGTM

与提议的className -> class重命名相关:我喜欢一个带有字符串数组的classes属性。 这将省去我在组件中进行大量字符串操作(或使用名)的麻烦。

我认为classes道具的唯一缺点是包含相同顺序的相同字符串的数组会导致在纯组件中重新渲染,而相同 CSS 类的字符串不会。 不过老实说,这似乎是一个小问题。 我认为大多数 React 开发人员已经知道在 props 中数组和对象的权衡。

@gaearon有向后兼容的计划吗? 也许遵循与 React Fiber 相同的路径,添加有关更改的警告并为大型代码库更新留出时间,而不会丢失新的更新。

关于classclassName

我知道无论我们走哪条路,我们都不会就此达成广泛一致。 人们对此有非常强烈的看法。 我想分享一下我的想法,希望它会有所帮助。

组件 API 应该是惯用的

有一个常见的论点是 React “匹配 JavaScript”,因此className是首选。 我认为这个断言被巧妙地误解了,所以我想稍微关注一下。

在 React 中,首先,我们关心使用 React 组件应该感觉像惯用的 JavaScript 。 这意味着如果我使用一个假设的<Table>组件,我希望它的 props 是 camelCase:

<Table
  rowHeight={10}
  headerBorderInset={5}
  renderRow={this.renderRow}
/>

我不希望在组件的公共 API中看到像row_heightrow-height这样的道具名称。 组件的 props 是一个对象(有点像“选项包”),我们通常期望这些选项是camelCase 。 这在 DOM 中可能并不总是惯用的,但是 DOM 在许多地方并不是很一致。 React 与绝大多数使用camelCase的 JavaScript 生态系统保持一致。

但是 DOM 呢? 这是它变得棘手的地方。

DOM 属性不仅仅是“JS 中的属性”

在 DOM 中,我们有属性和属性。 属性是您通常在 HTML 中看到的东西。 属性是你通常从 JS 设置的东西。 但至关重要的是, DOM API 既可用于设置属性,也可用于设置属性——它们甚至并不总是设置相同的东西。

node.value = 10; // setting a property
node.setAttribute('value', '10'); // setting an attribute

在许多情况下,这并不重要。 在某些情况下确实如此。 但也许不是人们从使用 React 时可能想到的方式(它对两者都有一个抽象)。

React 不仅仅是设置属性

一个常见的误解是,由于 React 目前对大多数 DOM 属性使用camelCase约定,这意味着 React 正在设置 DOM 属性。 这是错误的。

事实上,React 目前正在为它支持的几乎所有道具使用属性。 在某些情况下,例如value ,这会导致问题(正如我所讨论的,我们想要恢复)。 在其他情况下,这实际上很棒——因为我们不必在 React 包中包含支持的属性列表。 在引擎盖下使用属性是 React 16 的主要尺寸减少的原因。

我的观点是, React 在内部使用属性还是属性是一个实现细节——与 React DOM 元素 _API_ 是否应该使用属性名称、属性名称,甚至是其他一些有意义的名称无关。

仍然,让我们只使用属性名称?

好的,属性和属性是一个实现细节。 但是为什么不标准化使用 DOM 属性名称,因为它们是专门为“JavaScript”制作的呢? 今天的 React API 不就是这样设计的吗?

嗯,不完全是。 下面列举的只有一个props 对应一个真实的 DOM 对象属性:

<div
  tabIndex={1}
  data-id="123"
  aria-live="polite"
  nopin="nopin"
  itemType="http://schema.org/Movie"
  onClick={function() { alert('hi') }}
/>

具有讽刺意味的是,上面唯一一个具有与其对应的同名实际 DOM 属性的 prop(如果您不确定, tabIndex )实际上被 React 设置为属性!

因此,到此为止,您可能会发现它既不明确也不一致。 在某些情况下属性不存在(例如自定义、非标准属性),在某些情况下 React 可以提供更丰富的 API( data- vs dataSet )但目前不存在。

在某些情况下,React 故意选择偏离(React 中的onClickonclick DOM 属性),因为它对自定义 React 组件更有意义。 这是因为 React 组件通常会暴露更复杂的事件处理程序,例如onItemClick 。 如果您写的是<Button onclick>而是<Table onItemClick> ,那将是非常不一致的。 而且<Table onitemclick>不是 camelCase,我们希望在组件 API 中避免这种情况。

上面,我解释了 React 关于“始终使用 DOM 属性名称”已经不一致,React 甚至实际上并没有在内部使用属性(因此经验法则也没有描述实际的机制),而且在许多DOM 属性根本不存在,所以我们必须坚持允许属性名称。

如果不是属性名称,让我们保持一致并使用属性名称?

那么为什么不只使用属性名称呢? 这可能是合理的。 但是现在我们遇到了我们提出的第一个考虑因素。 使用 React 组件应该感觉像惯用的 JavaScript 。 但通常组件将至少一些 props 转发到底层 DOM 元素。

<Button
  borderColor='red'
  tabIndex={1}
 />

 // renders...

 <button
   tabIndex={1}
/>

自定义Button接受大小写不一致的道具会很尴尬:

<Button
  borderColor='red'
  tabindex={1}
 />

这迫使消费者始终记住某个道具是实际的 DOM 道具,还是只是组件合同的一部分。 即使这种区别也是模糊的——一个组件可能会选择首先通过某个道具,然后实际开始使用它来实现一些额外的逻辑。 “DOM 道具”和“其他道具”的界限在哪里?

我认为这是tabIndexcellSpacing和大多数其他与 DOM 相关的 props 遵循 camelCase 约定的主要原因。 这是因为它们通常最终出现在组件 API 中。

我们想让像Button这样的自定义组件更容易包装和转发它们,而无需在它们流入 DOM 时将它们“翻译”为属性名称,无需将非camelCase props 引入到自定义组件 API。

这也解释了为什么像data-*aria-*和自定义属性这样的道具是合理的例外(即使我们可以为它们制作更丰富的 API)。 它们很少传递给自定义组件。 通常,它们与 DOM 过于耦合,无法在自定义组件中使用——相反,它们成为具有更丰富的 camelCase API 的<Modal><Button>之类的实现细节。

React 属性已经不匹配 DOM 属性

如果“DOM 属性名称”约定不起作用,我们需要其他东西。 它是什么? 会不会是“属性名称的驼峰式版本”? 似乎这几乎总是已经检查出来了。

如果这听起来过于激进,请考虑我们已经在这样做。 我们支持一种叫做srcSet的东西。 但它的 DOM 属性名称是srcset 。 我们有autoCapitalize但 DOM 属性称为autocapitalize 。 我们有autoFocus但 DOM 属性是autofocus

当 DOM 属性名称与 camelCase JavaScript 约定不匹配时,我们已经偏离了它们。 这将我们带到class

最后: className vs class

将其设为className的部分原因是因为 React 正在设置 DOM 属性,而className是 DOM 属性的名称。

然而,正如我上面解释的,React 不再使用属性,除了三个或四个特殊情况。 更重要的是,React 甚至没有始终如一地使用 DOM 属性名称——相反,它使用在 JavaScript 中使用时看起来很自然的名称,而不管 DOM 属性和属性名称中的内部命名是否不一致。 这是因为 React 最关心的是让自定义组件的 prop 名称感觉“JavaScripty”。 从这个意义上说, tabindex不是“JavaScripty”——classclassName都是。

早期反对class的另一个论点是这样的代码不是有效的 ES3(与 IE8 相关):

// Not valid in ES3
// Valid in ES5
var props = { class: 'foo' };

但大多数人不再编写 ES3。 要么你正在使用像 Babel 这样的工具链,要么你可能针对的是 IE9+——React 现在甚至不支持 IE8。

所以class剩下的唯一不便是你不能这样写:

// Not valid at all :-(
const class = props.class;
const { class } = props;

但我认为,随着时间的推移,这个论点本身还不够有力。 React 不会强迫你使用解构或使用这个特定的变量名,并编写类似的东西

// Valid
const {class: cls} = foo;
const cls = props.class;

不是更努力了。

通常,人们传递class的次数远多于阅读它,因为许多组件包含不止一个内部<div>或其他宿主元素。 所以你最终写<div className>比想要解构class更频繁。 因此,对class的更改将节省比它引入的更多的键盘输入。

这里还有一个重要的点。

class向下传递到多个级别本身并不是一个很好的模式。 这对于库是必需的,但在应用程序代码中,它通常会导致组件脆弱。 因为有一百个不同的调用站点,每个调用站点都附加了一个不同的类,所以它们的样式总是会中断,从而导致级联错误。 因此,首先鼓励解构class的价值尚不清楚。 我认为你需要再写一行代码来从 props 中读取它是很好的(或者你可以只使用props.class而不考虑它)。

如果您正在编写一个非常接近 DOM 的组件(因此将class作为道具是有意义的),您可能也希望转发其他道具。 所以你可以在解构中使用 rest 语法:

// Valid in ES2018

function Button({ color, ...rest }) {
  const buttonClass = rest.class +  ' Button-' + color;
  return <button {...rest} class={buttonClass} />
}

如果您不需要修改它,那么您可以直接转发{...rest}而无需从中读取class 。 因此,解构限制可能有助于鼓励更好的组件设计。

为什么不同时?

why not both

最后,我们不能同时支持classclassName吗? 在某种程度上,我们已经这样做了,但是 React 会为此大喊大叫并发出警告。 有一个原因。

如果我们在没有警告的情况下同时支持这两种方法,那么社区将分裂为使用哪一种。 npm 上接受类 prop 的每个组件都必须记住转发两者。 如果即使中间的一个组件不配合并且只实现一个道具,该类就会丢失 - 或者您可能会在底部“不同意”每个“不同意”的classclassName其他,React 无法解决该冲突。 所以我们认为这会比现状更糟糕,并希望避免这种情况。

概括

如果 React 今天是开源的,似乎允许class (在概念上更接近大多数人的期望,为最常用的 prop 键入更少的内容)的优点超过了缺点(为了拦截它而需要更多的键入 - 在在这种情况下,您可能只需要扩展运算符)。

我们过去认为的缺点(与 DOM 属性不一致)是没有实际意义的,因为我们不再设置 DOM 属性,甚至也没有努力与它们保持一致。 相反,我们的目标是在 React 组件的消费端拥有一个基于属性的 camelCase API——我们已经几乎一致了。 而且class="Button"显然比className="Button"更方便。 事实上,如果 DOM API 是在今天设计的,它可能会允许你设置.class属性,因为在这样的赋值中使用class的限制在 ES5 中被取消了——大约十年前。

唯一剩下的大缺点是迁移成本。 我们会仔细评估这一点。 但是,如果我们无论如何都要进行大量更改,我们也许也可以进行此更改并永久修复它。 我们不会轻易考虑这一点,我们会考虑您的所有担忧。

注意:这可能适用于与 camelCased 属性名称不匹配的其他 React 道具名称。

@renatoagds

有向后兼容的计划吗? 也许遵循与 React Fiber 相同的路径,添加有关更改的警告并为大型代码库更新留出时间。

正如我所指出的:

我们在 Facebook 拥有超过 50,000 个组件,以确保我们对迁移策略保持诚实。 除了一些有针对性的修复或自动代码模块之外,我们无法重写产品代码。

因此,我们肯定会像往常一样尝试使迁移策略尽可能顺利。 如果不顺利,我们将无法自己进行更改。

re: className -> class,我对任何决定都很满意,我绝对可以看到为新用户更改类的例外情况,以及更短代码行的附带好处。 虽然,他们仍然需要了解其他 camelCase 名称。

所以上课剩下的唯一不便是你不能这样写:

const { class } = props;

但我认为,随着时间的推移,这个论点本身还不够有力。 React 不会强迫你使用 > 解构和写作

const class = props.class;

是不是更努力了。

两件事(可能很小):

  1. const class = props.class不是无效的 JavaScript 吗? 我不认为是这样,并且在快速测试中 Chrome 不喜欢它。 此外,这篇文章表明它是无效的。

  2. 对于编写这样的组件的人来说,我可以看到这种变化是一个(再一次,可能很小)令人沮丧的领域: nvm(请参阅下面的更新

const { oneProp, twoProp, className, ...rest }  = this.props;

// do stuff with oneProp, twoProp, className

return (
  <div
    someProp={prop}
    anotherProp={anotherProp}
    className={someClassName}
    {...rest}/>
);

在此更改之后,这将需要类似于...

const { oneProp, twoProp, ...rest }  = this.props;

// do stuff with oneProp, twoProp, this.props.className

return (
  <div
    someProp={prop}
    anotherProp={anotherProp}
    {...rest}
    class={someClassName}/>
);

绕开这种变化并非不可能,但是在以这种风格编写和阅读组件时要记住一点。

更新

没关系,

const { class: className } = this.props;

成功了。

唯一剩下的大缺点是迁移成本。 我们会仔细评估这一点。 但是,如果我们无论如何都要进行大量更改,我们也许也可以进行此更改并永久修复它。 我们不会轻易考虑这一点,我们会考虑您的所有担忧。

幸运的是,如果使用 CSS-in-JS 方法(如 Aesthetic),这很容易缓解。 感谢您的精彩写作!

关于属性名称的随机提示,我发现了出色的项目, svg2jsx非常适合将大型 SVG 转换为在 React 中使用!

@jamesplease对不起,我的大脑一片空白——你是对的。 已编辑。

@jamesplease你是对的。 对于默认值,这也经常与 JSON 一起使用,太烦人了!

const { default: defaultVal } = property

当您更改事件系统时,很高兴看到类似于 Inferno 的 linkEvent 函数的东西,这样我们就可以在功能组件中使用 props 进行事件处理,而不必在每次渲染时创建一个匿名函数。

className -> class将对生态系统产生巨大的变化,大量未维护的组件将变得不兼容,如果无法修补它们将无能为力。 也许有一些像StrictMode这样的包装器,它为树中更深的组件禁用此更改以提供渐进的迁移路径?

对于编写如下组件的人来说,我可以看到这种变化是一个(再一次,可能很小)令人沮丧的领域:

const { oneProp, twoProp, className, ...rest }  = this.props;

// do stuff with oneProp, twoProp, className

return (
 <div className={someClassName} {...rest}/>
);

只是不要破坏它。

const { oneProp, twoProp, ...rest }  = this.props;

return (
  <div
    {...rest}
    class={'something ' + rest.class}
  />
);

@gaearon

React 是否在内部使用属性或属性是一个实现细节

老实说,这似乎也是一个问题。 在某些情况下,DOM 元素的行为会有所不同,具体取决于您是设置属性还是属性。 React 不可能知道所有的差异,但是元素的用户可以知道他们使用的元素。 对属性、属性和事件的显式控制将使作者摆脱这种情况。

@justinfagnani如果您有希望我们更改的特定内容,您介意使用您建议的 API 提交单独的问题吗? 这听起来有点超出了这个问题的范围。

@sompylasar

className -> class 将对生态系统产生巨大的变化,大量未维护的组件将变得不兼容,如果无法修补它们将无能为力。 也许有一些像 StrictMode 这样的包装器,它为树中更深的组件禁用此更改以提供渐进的迁移路径?

我同意——我们仍在权衡利弊。 什么都没有最终确定。

但在实践中,未维护组件的问题并不是什么新鲜事——它会在每个 React 主要版本中出现,因为专业中的定义会发生变化(否则我们无法继续前进,而且我们没有保留所有遗留代码的奢侈永远不像在服务器环境中的捆绑包)。 当PropTypes移动到单独的包中时会出现同样的问题,并且会在UNSAFE_生命周期重命名时再次发生。 未维护的包会被分叉或打补丁。 我们意识到这是一个很大的时间沉没,这就是为什么我们避免在一年中做一个以上的大专业。 对于负担不起帮助的人来说,通常等待几个月再转到新的专业是最好的策略,因为早期采用者铺平了道路并恢复了废弃的套餐。 然后我们一起前进。

再说一次——我非常理解你的犹豫,但这与过去发生的或将来可能发生的其他重大变化并没有本质上的不同。 与往常一样,我们将投入大量精力和重点放在可以运行以转换大部分代码库的自动化脚本上,并且您也可以在其他包上运行(并将 PR 发送给它们 - 或在它们的最后状态分叉它们)。

不管您的决定如何,反对class的另一个论点是可搜索性。 当您想在使用 JS 类组件的 ES6 代码中查找使用 CSS 类的组件时,有多少误报会让您通过class进行搜索? 是的,您可以搜索class={ ,但是在 JSX 中解构作为 JS 中的对象创建的道具呢? (我反对大量使用解构道具,但它们仍然被使用)当然,我们需要在代码编辑器中更好的上下文感知的基于 AST 的搜索工具,但现在我们只有文本和正则表达式。 当然类型系统可能有助于跟踪对象传递,但大量人口尚未采用它们。

即使现在不会引起任何问题,使用保留字也不适合我; 我们可以肯定地说rest.class (例如)在 x 年内对语言没有意义吗?

@GeordieP如果它今天有效,明天就不会中断。 这是 JavaScript 如何发展的核心原则,也是其许多特质的原因。

@gaearon 那么公平。 如果它是一个足够大的胜利,我说去吧。

@sompylasar我通常搜索className=className: ,似乎这两个都可以与class一起使用。

请摆脱className ,看在上帝的份上, htmlFor 。 我不是 DOM 开发人员,如果我必须访问本机 DOM 方法,通常会有一些非常非常错误的事情。 我让人们加入 React 的最大挑战是 JSX 对 DOM 的抽象以及它奇怪的替换 HTML 属性。 一切都在被转译,此时没有理由担心保留字。 国际海事组织。

不确定这是否会为现有讨论添加任何内容,但似乎应该有更好的理由来更改className

将初学者 React 学习者从一个稍微不直观的名字中拯救出来值得每个人都必须更新他们的项目和行为吗?

作为一个自由地使用解构的人,与我写class而不是className的罕见情况相比,必须记住这个规则的新例外可能是一个更大的心理问题。

另外,初学者不会对目前使用className的大量材料(如博客/repos/等)感到困惑吗?

最后,正如@sompylasar所说,这会损害我代码库中的搜索能力。

也许这是一个制表符与空格类型的论点,但我不完全理解为什么这种改变是必要的。 除非这是随着时间的推移您希望对 API 建模的方式发生较大转变的一部分,否则这似乎是一笔巨大的成本,却收获甚微。 也就是说,我肯定会使用你决定的任何东西😅。

有点离谱,但令人遗憾的是,没有人(据我所知)有想法制作一个 html/css/svg -> jsx 转换器,以便通过许多微不足道的更改来轻松迁移到 React,以将 HTML 属性映射到反应道具。

@jxub - 作为 2014 年黑客马拉松的一部分,我构建了一个 HTML 到 JSX 转换器: https://magic.reactjs.net/htmltojsx.htm。 不过,我不确定它是否能很好地处理 SVG。 黑客马拉松项目是制作一个脚本,通过使用 React (https://github.com/reactjs/react-magic) 来“ajaxify”一个纯 HTML 网站,其中一部分需要我构建一种方法来创建一个 React 组件来自一大块 HTML,所以我将 HTML to JSX 部分作为一个单独的独立页面发布。

我们仍然关心支持 IE11,但我们可能不会尝试消除一些现有的浏览器差异——这是许多现代 UI 库所采取的立场。

@gaearon - 有哪些现代 UI 库不能平滑浏览器差异的例子? 对我来说,这是使用图书馆的主要原因之一。

阴谋论:整个班级名称/班级新闻是一件引人注目的有争议的事情,每个人都会立即关注和争论。 要么是为了吸引整个返工项目的注意力,要么是分散在阴影中发生的更大的事情,或者提供一件可以稍后收回的东西,而其余的将被接受,就像下面的轶事:

伟大的戏剧艺术家 Tyshler 创作风景素描,在角落里画了一只小绿狗。 而当其中一位招生委员问:“我什么都喜欢,但这只狗呢?”时,这位艺术家带着遗憾的叹息贴在她身上。

这种变化背后的真正原因尚不清楚,但它们已经使这个新升级项目的受欢迎程度飙升,社区围绕 React 议论纷纷。

如果支持被动事件监听器在 React Fire 的范围内就好了,这是移动设备上的一个重要特性。

6436

感谢您为此付出的所有辛勤工作,但请重新考虑className -> class

我们都曾经是 React 新手, className并没有阻止我们学习和热爱 React。

我记得当我在 jsx 中使用 vue 时,他们已经有class而不是className ,我不同意将 className 更改为class ,因为 React 是 Virtual DOM 的先驱, 并代表它自己的 DOM。

在 React 根目录而不是文档中附加事件

@gaearon这是否意味着在测试环境中我不必将元素附加到文档中就可以调度真正的浏览器事件并调用与它们关联的处理程序? 必须这样做是非常违反直觉的,我敢肯定,许多不熟悉 React 内部结构的开发人员会感到困惑,浪费大量时间编写测试并引发事件模拟和糟糕的测试实践。

这让我注意到另一个问题,我们可以做一些关于react-dom/test-utils的事情吗? 鉴于我们都知道与之相关的所有问题,我对可能删除Simulate特别感兴趣,当然对react-dom本身进行必要的更改,以便真正不需要它了。 这可能在范围内吗?

/cc @kentcdodds

我喜欢 React Fire 的方向和大局观。 到目前为止,这些看起来像是需要努力实现的巨大变化。

最喜欢宣布的更改,但我对className的更改持怀疑态度。

React 不会强迫您使用解构或使用这个特定的变量名,并且编写类似 (...code snippet...) 的东西也不会花费太多精力。

虽然编写起来并不费力,但根据我目前的经验,我希望向其他开发人员(尤其是来自其他语言的开发人员)解释它会_way_ 困难。 另一方面,在我们公司使用 React 的这些年里,我猜只有一两个开发人员对className感到困惑,并且只是将其作为 Reacts API 接受,以便在几分钟内设置类名。

(在我个人看来,当我 _love_ 破坏时,重命名语法本身对初学者来说有时感觉很奇怪,因为它与在导入时重命名不同,后者看起来非常相似,并且可以与默认值之类的东西结合使用。一个 _could_ 只是不使用破坏然后, 但这将是我们目前在公司编写的所有其他代码的_big_ 例外。来自其他人的经验当然可能不同,但这是我对这个问题的看法🙃。)

伟大的

也对className的变化持怀疑态度。 这是事物计划中最微小的变化之一,但它在这里吸引了大量的评论讨论。

当有这么多其他好东西被宣布时,是否真的值得花这么多政治资本进行变革?

从我的立场来看,如果你正在做出决定,其中部分理由是“并且写出类似............不是_那_更多的努力。”,那么这个决定必须有一个_巨大的_上升空间,并且className -> class更改与已宣布的其他所有内容相比并不相同。

这将是 🔥 React Fire 的重大进步

关于class v/s className ,我认为我们应该提醒自己 JSX ≠ React。

由于 JSX 是一种 _DSL_,它的设计看起来像 HTML,所以最好让它尽可能接近 HTML。 当然它在 DOM API 中被称为className ,但大多数人使用 JSX 可能是因为他们不想直接处理 DOM API。

如果 React 的 API 与 DOM API 紧密匹配更有意义,那么我希望在转译中进行映射是可以/可能的:
<img src="avatar.png" class="profile" />React.createElement("img", { src: "avatar.png", className: "profile" })

让 JSX 语法成为 HTML 的干净超集是非常有价值的。

添加到@mhenr18所说的内容。

目前的情况:

  • 反应不一致
  • API 是驼峰式

建议状态:

  • 反应不一致
  • API 是驼峰式
  • className -> class

感知的好处:

如果 React 今天是开源的,似乎允许类的优点(在概念上更接近大多数人的期望,最常用的 prop 输入更少)大于缺点(拦截它的输入稍微多一点——在这种情况下,你会可能只是想要传播运算符)。

实际缺点:

  • 依赖className的整个生态系统停止工作(巨大的升级工作)
  • 大量的书籍、教程、示例、代码、帖子、文章变得如此轻微地无效
  • 剩下的唯一有效的 JS 是额外的输入const {class: cls} = props 。 普通 JS 中所有其他可能的用例都变得无效
  • React API 仍然不一致,并打破了进一步的假设(为什么htmlFor不是for等)

如果我是产品经理,我对变化的第一反应是:什么?

@gaearon您可能已经考虑过这一点,请使用“React Fire”或类似关键字标记 PR。

问题通常被正确标记,PR 有时没有。 这有助于潜在的贡献者。
这是来自我在整个 Fiber 开发过程中尝试通读 git 历史以查找 React Fiber 和 React Reconciler 相关提交时的经验。 它可以帮助我们这些试图弄清楚正在发生的事情并看看我们是否可以在某些方面做出贡献的人。

我还认为将className重命名为class将导致如此大的迁移工作和新开发人员的问题。
className属性是如此可见且被大量使用,以至于它实际上会破坏所有依赖于 react 的库。
这还不够,大多数教程都会被破坏。 从文章中复制和粘贴的新设备会想知道“为什么这不起作用,它说className不是有效的道具”。
所以前辈必须提供帮助,而我们没有任何收获,因为我们仍然需要解释为什么它不能像你期望的那样工作。
事实上,解释你必须使用className来定义组件上的类需要不到一分钟的时间,而且很容易理解。 向每个开发人员解释为什么他们从className更改为class需要更长的时间并导致更多的挫败感。

一个词所需的所有努力。
它不会改变 react 的行为方式。
它不会促进 react-dom 的发展。
它不会提高开发人员的工作效率超过一周的反应。
它只会破坏一切。

请想一想,真的值得吗?

我多年来一直在使用babel-plugin-react-html-attrs并且它一直很好地为我服务,我不认为将className重命名为class是一个好主意。 通过像我提到的那样的插件更好地实现它。

不是有一个Babel 插件来处理整个“ class v className ” / “ for v htmlFor ” 的情况吗?

我希望可以按原样支持 html 属性,同时保持与已经做出的命名决定的向后兼容性。

已经有 babel 插件可以进行转换的事实可能证明应该可以在核心 JSX 转译器本身中支持它。 但是,将其作为官方规范将使每个人的事情变得更加容易和可靠。

我不了解 React 的内部结构,所以不能说太多关于真正的可行性。 仅在用户友好性方面表达我认为“应该”的方式。

请重新考虑classNameclass 。 正如上面所说,收益几乎不存在,但也有真正的缺点。

一个是对于我们使用 Haxe 作为一种语言来编写 React 应用程序来说,这不仅是一个突破性的变化,而且只会阻止我们编写_任何_ React 应用程序。

class是大多数编程语言中的保留关键字,我们不能再操纵这个道具,这使得 react 应用程序几乎不可能(祝你好运,在不操纵类的情况下创建一个真实的)。 htmlFor vs for也是如此,遗憾的是(这个真的很难看,但我很感激它的存在)。

哦,顺便说一句,可搜索性......想象一下你在谷歌搜索“React 类”,你会得到混合信号:React 类组件,React 类属性。 你用谷歌搜索“React className”,你会得到过时的文档(上面提到的人们除了代码升级之外,这种变化还带来了大量的升级工作)。

这个项目的目标是为社区创造更多的工作,为互联网创造更多的噪音和混合信号吗? 我希望不是。

是的,Web 和 JavaScript 生态系统一直在努力与过去的愚蠢错误保持向后兼容,但是这种向后兼容的努力使它能够在没有严重碎片化的情况下发展到如此规模。

我明白没有改变就没有进步,我自己也接受了早期FB的座右铭,即打破事物以快速行动(也有一个如何提前将它们重新组装回来的计划)。

如果您如此坚持以至于确实需要进行此更改,请说出更改的真正原因。 它不可能是“难学”的东西,对于强大的 React Core 团队来说听起来太肤浅了。 你绝对应该有一些想法。

@sompylasar我通常搜索 className= 或 className:,似乎这两个都适用于类。

另外,祝你好运直接在 github 上这样做 =/

我已经阅读了这里的所有评论。 我对更改很好,但不确定class 。 主要原因是它不适用于 JSX 2.0 的计划。 关于快捷符号(就像我们现在在对象中所使用的那样)。
其他一切似乎都是非常好的改进。
等待最终决定:) 感谢你们的惊人努力!

在您的一条评论中,您提到“如果今天有效,明天应该有效”。 在我问之前请记住这一点;)。

我维护了一个名为 RMWC https://jamesmfriedman.github.io/rmwc/的 UI 库,它针对所有版本的 React 回到 15.4。 我已经能够维护一个统一的 api 界面,但是将 className 更改为 class,将 onChange 更改为 onInput,并且彻底检查事件系统将使这几乎无法继续。

是否有任何可能的“兼容”层可以在引擎盖下翻译其中的一些内容? 所以我可以写任何版本的反应火,但继续在较低的运行时运行。

如果不是,我希望我奇怪的代码会变得更奇怪。 👀

如果className真的必须更改为class ,请同时将htmlFor更改为for
因为classfor在我们解构props时最初是无效的。

如果 React 有自己的 API 可以规范化许多属性名称以形成一致的 API,那么className肯定是完美的选择。 在 camelCase 惯用语之上的一个额外惯用学习,加上它映射到 DOM 属性名称(就像其他一些 JSX 属性)的事实,与每次使用时都必须将其解构为特殊情况相比肯定很好一个带有它的道具对象。

我觉得,到目前为止,您已经听到了很多反对现状的声音(“为什么我们不能上课?!”),而每个使用它的人都保持沉默; 与古老的格言一致,即人们更有可能给出负面评价而不是正面评价。 就我个人而言,我认为每次出现这个道具时,一个微小的学习曲线都比特殊外壳要好得多。

我想我希望围绕它看到更多的民主——我认为这个非常具体的改变可以由委员会来完成(它本质上是一个让你考虑这个改变的伪委员会)——我很高兴能加入失败的一方。 只是为了让它每天影响最少的人。

顺便说一句,其他一切看起来都很棒,尤其是活动的东西👌🏻

等待新的更新

@gaearon是否值得考虑您自己的示例:

const { oneProp, twoProp, ...rest }  = this.props;

return (
  <div class={'something ' + rest.class} {...rest}/>
);

包含错误并且无法按预期工作? 它可能不像“不要破坏它”那么简单。

我是唯一一个不担心类是类名的人吗? 如果你要问我反应有什么问题,那我什至不会想到。

不过,更新是免费赠品,我喜欢免费赠品。

我是唯一一个不担心类是类名的人吗?

我一点也不担心上课。 IE11 的细微错误会更有趣(尽管如此,我仍然对这些变化非常满意)

如果支持被动事件监听器在 React Fire 的范围内就好了,这是移动设备上的一个重要特性。 #6436

我同意。 这绝对在这项工作的范围内。

@gaearon - 首先感谢。

您是否考虑过进行一项调查,以收集有关人们如何使用 react 以及正在使用哪些 API 以及哪些令人困惑的信息?

虽然 React 是迄今为止我最喜欢的前端开发堆栈,但我发现在学习和第一次使用它时有一些技巧。 我不想仅仅列出我教过的人个人感到困惑的内容。

我发现它在我个人参与的项目(Node、Bluebird 等)中很有用。


就我个人希望在核心中看到的内容而言:我更喜欢更简单的非全局依赖注入支持,更好和更一致的事件处理(您已经在讨论)。

您是否考虑过进行调查以收集有关人们如何使用 react > 以及正在使用哪些 API 以及哪些令人困惑的信息?

我认为 react-native 有一个 canny.io 我没有意识到 react 没有

我维护了一个名为 RMWC https://jamesmfriedman.github.io/rmwc/的 UI 库,它针对所有版本的 React 回到 15.4。 我已经能够维护一个统一的 api 界面,但是将 className 更改为 class,将 onChange 更改为 onInput,并且彻底检查事件系统将使这几乎无法继续。

是否有任何可能的“兼容”层可以在引擎盖下翻译其中的一些内容? 所以我可以写任何版本的反应火,但继续在较低的运行时运行。

我同情你的担忧(我也写了我相当一部分的图书馆)。 然而,由于改变任何东西都有很多权衡,我们倾向于错误地帮助人们升级而不是帮助人们支持多个版本。 这并不意味着我们根本不这样做(我们确实为库作者发布了一个 polyfill,用于在 16.3 中进行生命周期更改),而是我们没有针对这个用例进行优化。

我的建议是,如果有什么不兼容的地方,当我们削减一个新的专业时,就削减一个新的专业。 如果他们愿意,人们可以继续使用旧的主要版本的库。 我知道维护它需要付出更多的努力,尤其是如果您继续开发它,但是单个 hacky 代码库是否比两个不同但一致的代码库更好是值得怀疑的。

@jamesmfriedman应该可以(并且不太复杂)使用codemod(自动)更新到新API,然后(作为构建过程的一部分)转换(再次使用codemod)到旧API。 然后发布这两个包并根据 React 版本动态地要求它们。

这是一些工作,但它可以完成一次(例如作为 webpack 插件或 npm install 脚本?)并且应该不难。 我认为这是一种可以发布一次并在所有库中使用的东西。

就像专门用于库的编译时兼容性层。

我支持为 for 删除 htmlFor。

您认为同时支持 className 和 class 的桥接版本是个好主意吗? 它将允许开发人员使用较旧的第三方 React 代码,而他们当前的第一方代码可以面向未来。 一旦第三方更新,只需删除 bridge 包即可获得完全优化的 React DOM。

React API 仍然不一致,并打破了进一步的假设(为什么 htmlFor 不适用等)

当我说for也应该改变时,我想你错过了最后一句话。 然后我认为我们将与“驼峰式属性名称”完全一致,除了一两个罕见的 SVG 属性。 我们也可以改变。

不是有一个 Babel 插件来处理整个“class v className”/“for v htmlFor”的情况吗?

我看到很多人提到这一点,所以我想澄清一下。 Babel 插件不是进行这种转换的好地方,因为它不适用于以下情况

const props = {
   class: "foo"
}
<div {...props} />

你传递class但在组件的 props 中获得className也是没有意义的。 或者,如果插件仅针对平台元素,那么将button替换为Button会更改class属性的编译结果会很奇怪。

为此使用 Babel 插件只会掩盖您正在编写的代码的语义,并导致更多的混乱。 在我看来,这是一个比只允许classNameclass更糟糕的解决方案。

有趣的事实:这是一个非常旧版本的 JSX 编译器的工作方式。 由于令人困惑,此行为已被删除。

令人敬畏的变化。 . .

惊人的! 感谢所有贡献者为带来如此激动人心的更新而努力。
我不知道className > class是这么大的丑闻。 我个人已经习惯了。

减少捆绑包大小和升级事件系统听起来很有希望。 超级激动!

我真的很期待将事件系统的 polyfill 分离为单独的包。
但是 className > class 是否过于激进,你知道,React 的影响太广泛了。
这会不会导致很多系统无法预料?

删除三分之一的 React DOM 会很好。

在 Web 应用程序开发中使用 React 会很棒。

命名空间也可以很好地响应特定的道具,例如keyref 。 例如

<Foo @key="foo" @ref={callback} prop="hi" />

这已经在这里讨论过 - https://github.com/facebook/jsx/issues/66

@elado虽然这可能是我们将来想做的事情,但我认为它超出了范围,因为它会影响非 DOM 特定的 API。

虽然这很令人兴奋,尤其是总是欢迎捆绑包大小的减小。 我担心的是,Facebook 的人们低估了破坏 API 更改可能给生态系统和社区带来的惯性、痛苦和碎片化。

确实,他们在 FB 有大量组件需要担心,但他们获得的优势(我在这里假设)是他们对外部开源 React 库的依赖最小,因为他们很可能在内部构建大部分组件。 对于使用大量开源库的其他人来说,从许多库中获取 Proptypes 确实需要付出很大的努力、等待和挫折(我是从升级大型 React 代码库的真实经历中说的)。 快速行动和打破常规可能不适用于想要以有限资源建立稳定业务的人。

我真的很喜欢 react,API 很简单,而且我个人没有时间去学习和适应它的语法。 因此,我真的敦促维护者仔细评估任何生态系统范围内的重大更改的利弊,并务实地考虑更改是否需要强制整个生态系统进行重写。

除此之外,我非常感谢构建、维护和升级 React 的努力,以及背后工程师的热情 :)

这些未来的 {...updates} 是🔥

className -> class :我认为在 JSX/object 声明之外定义类属性时,这种情况并不罕见。 在这种情况下,我们将不得不对同一事物使用不同的命名,这会导致不一致,增加代码复杂性和认知负担。
建议的更改不会从我们的代码库中删除不匹配的属性/道具名称 - 由于语法限制或使用本机 DOM 时,它会存在于某处。 对于这个命名问题,我们已经“标准化”(并且在这一点上很好地建立了)解决方法,这是一件好事。
目前className可以在任何地方一致地使用,总是引用相同的东西——即使在使用原生 DOM 时也是如此。 实际上,react 可能是字面上唯一的地方,我们将被迫使用class来引用类属性。
className似乎从一开始就非常不必要并且有点令人困惑,但后来证明它非常实用并且相对容易习惯。

我也会为dangerouslySetInnerHTML摆脱额外的对象{ __html } ,因为它似乎真的没有必要,但与迁移相关的问题可能不值得(并且可能与这个问题完全无关)。

虽然其他变化产生的情绪要少得多,但它们更加有趣和重要,所以感谢 fb 团队的努力。

重大更改越多,升级实际用户应用程序所需的时间就越长。 就我个人而言,我已经远远落后于最新的最伟大的 React(这让我感到难过),因为以前版本的 React 已经破坏了一些东西,这些东西需要我依赖的库来升级,然后引入了延迟。

理想情况下,我希望处于以下情况:

  • 下游 React 库在新版本上重写代码,为我的用例引入错误
  • React 增加了很酷的新功能 / 减少捆绑包
  • 旧的库版本在新的 React 上仍然可用
  • 是的,我可以在 React 启动后立即使用新功能,然后等待库修复错误

在实践中,它更像是:

  • 库重写代码,引入错误
  • React 发布新的重大变化
  • 旧图书馆不再工作
  • 新库最终更新
  • 错误可能仍然存在
  • 我很长一段时间都停留在过时的 React 上,而不是(引用 Ken Wheeler 的话)“新的热点”。
  • 我很难过 :(

从“交付代码的角度”来看,每一次重大的重大升级都会成为一个巨大的烦人的技术债务,包括更新所有依赖项、重新测试所有内容、然后寻找新的错误以查看是否有解决方法。 除非存在严重的漏洞或者做某事确实不切实际(而且门槛很高),否则它会被取消优先级。

不幸的是,尽管它已经摆脱了 0.x 的范式,并且尽管试图成为一个核心 Web 库,但 React 仍然在搅动版本号,这意味着需要花费大量时间来保持静止。

基本上我要说的是,请尝试计划一个 API,以允许未来的重大变化不会被破坏。

(IE11 的事情也很可悲,因为您正在弃用不是 EOL 的浏览器 - 最后一次发布是 52 天前。我认为 React 团队会发现这只是将工作推给 Facebook 团队以及所有外部和内部库团队以减轻它反而)。

@urugator

我也会摆脱额外的对象 { __html } for dangerouslySetInnerHTML 因为它似乎真的没有必要

这是故意设计的明确且难以意外使用。 如果它被删除,那么任何未经处理的数据都可能意外地传递给危险的SetInnerHTML。

@philipwhiuk

基本上我要说的是,请尝试计划一个 API,以允许未来的重大变化不会被破坏。

重大变更对于改进技术是必要的,React 负责任地处理不频繁的批量重大变更。 如果没有像删除 componentWillReceieveProps 这样的破坏性更改,我们就不会拥有像 React Suspense 这样的好东西,并且社区中的软件将更加难以维护,因为旧的 API 会永远存在。 如果一次升级一个主要版本,应该没问题。

IE11 的事情也很可悲,因为您正在弃用不是 EOL 的浏览器 - 最后一次发布是 52 天前。

没有人反对 IE 11。React 的当前版本实际上需要为 IE 11 中的某些功能添加 polyfill,因此建议的更改可能会对 IE 11 开发产生大致相同的影响。 https://reactjs.org/docs/javascript-environment-requirements.html

我也会摆脱额外的对象 { __html } for dangerouslySetInnerHTML 因为它似乎真的没有必要

@urugator - 值得一提的是,在 Facebook 内部, __html最常见的用法是将服务器渲染的 HTML 插入到 React 组件树中。 对于该用例,我们在服务器端构造__html对象,并在客户端设置 lint 规则。 在服务器端,我们有将XHP序列化为具有__html属性的对象的方法。 这确保了我们不会在任何地方引入任何安全漏洞,因为 XHP 与 JSX 非常相似(它实际上是 JSX 的主要灵感来源)并且还具有 XSS 保护。

本质上, __html对象标记了一个我们知道的 HTML 字符串,它已经在某个地方进行了清理,并且可以安全地直接插入到 DOM 中。 原始字符串更难处理 - 你如何判断它是否已被清理与是否有人意外返回了一些原始用户输入(并因此引入了 XSS 漏洞)?

所以是的,它是故意难以使用的,因为在大多数应用程序中不应该有很多用例,并且应该合理地包含用例。 通常你不应该直接在你的 React 组件中构造__html对象,而应该有一些函数来返回它(查看文档如何使用createMarkup函数:https://reactjs. org/docs/dom-elements.html#dangerouslysetinnerhtml)

我担心的是,Facebook 的人们低估了破坏 API 更改可能给生态系统和社区带来的惯性、痛苦和碎片化。

感谢您提出这个问题。 我完全明白你来自哪里。 但我想指出,React 团队中的大多数人在被聘用之前一直在 Facebook 之外使用 React——通常是在大型应用程序上。 所以我认为这有助于我们理解影响开源用户的各种问题。 我已经使用 React 两年了,并且非常清楚地记得由例如父/所有者上下文切换引起的碎片。 关键是要有一个好的迁移策略——这同样适用于上述所有变化。

确实,他们在 FB 有大量组件需要担心,但他们获得的优势(我在这里假设)是他们对外部开源 React 库的依赖最小,因为他们很可能在内部构建大部分组件。

对于开发的产品方面来说,这在历史上一直是正确的。 然而,自从创建 Yarn 并将其与我们的 Web 存储库集成以来,我们已经看到越来越多的第三方组件用于内部工具页面——它们本身的表面积比 Facebook 消费产品大得多。 因此,我们也需要一种逐步迁移第三方软件包的策略。

与许多其他公司不同,我们在整个代码库中使用相同版本的 React。 所以我们也有独特的挑战(例如,我们不能只是“等待”升级某些产品)。 这肯定会给我们带来更大的压力,让我们有一个好的迁移策略并作为压力测试。

对于使用大量开源库的其他人来说,从许多库中获取 Proptypes 确实需要付出很大的努力、等待和挫折(我是从升级大型 React 代码库的真实经历中说的)。 快速行动和打破常规可能不适用于想要以有限资源建立稳定业务的人。

如果您好奇,我们仍然有类似的代码

React.PropTypes = require('prop-types')
React.createClass = require('create-react-class')

在我们的代码库中,因为我们也负担不起完全迁移到“白板”。 但是今天从 React 开始的人们,以及我们代码库中更现代的部分,不必承担那么大的重量。 这就是我们的想法——我们希望为新的 React 用户选择更好的默认值,但为我们自己和其他所有人提供一个好的迁移故事,即使其中的某些部分可能是 hacky。

我可能没有足够清楚地传达这一点,所以我道歉。 任何大的变化都需要一个复杂且执行良好的迁移策略,考虑到第三方库需要很长时间才能更新,不同的版本可能需要共存等。例如,使用class计划不仅仅是一夜之间改变它。 如果我们想这样做,我们会想知道如何推出它 - 可能有一个我们允许两者的宽限期,或者一个帮助者使它更容易做到,然后逐渐淘汰旧名称. 我还没有具体的策略,但很明显,如果没有好的策略,改变是不可行的——对我们和你来说都是如此。 这是我们非常重视的事情。

(IE11 的事情也很可悲,因为您正在弃用不是 EOL 的浏览器 - 最后一次发布是 52 天前。我认为 React 团队会发现这只是将工作推给 Facebook 团队以及所有外部和内部库团队以减轻它反而)。

我不明白你指的是什么。 我没有说任何 IE11 被“弃用”。

我的帖子只是说,对于像 IE11 这样的浏览器,我们可能需要比现在更多的 polyfill。 React 在 IE11 中已经需要一些polyfill。 我并不是说我们想要破坏它——它仍然有很多用户——但是如果你想让它工作,你需要包含更多的 polyfill。 这对我来说似乎完全公平。

此外,我们不会将工作“推”给 Facebook 的其他团队。 如果我们破坏了某些东西,我们就必须修复它。 这就是为什么我们如此关心迁移策略的原因——我们通常必须自己执行它们。

回复:你的其余评论——我们绝对不会为了它而做出重大改变。 事实上,我们正在非常非常努力地避免破坏性更改。 React 的许多部分复杂且难以维护,但我们保留它们的唯一原因是我们试图支持遗留 API,即使它们已被明确标记为不稳定。 然而,在某些时候,问题的重量会累积起来,我们需要从头开始,继续前进并修复它们。 我的 OP 帖子中的问题正是这类问题。 他们不值得独自进行重大变革。 但综合起来,我们认为他们值得付出努力。

我不明白为什么人们对此如此消极。 在您的依赖项完成之前不要升级?

class vs classNamefor vs htmlFor的关键字问题不是 jsx 编译器可以处理以覆盖保留字吗?

我真的只会担心变化是否足够大以至于搜索结果给出过时的答案......就像谷歌搜索“angular -angularjs -angular1.x”等时引入的痛苦角度2+

除此之外,我欢迎所有的变化!!!

@gaearon

你说

“我们可能需要放弃与一些旧浏览器的兼容性”

这是我遇到问题的 drop 兼容性部分,而不是下面的 polyfill 部分。 回到黑暗时代是我的担忧。

关于过程。 这种“问题”不是 RFC 流程的设计目的吗?

这是我遇到问题的 drop 兼容性部分,而不是下面的 polyfill 部分。 回到黑暗时代是我的担忧。

我说的是 IE10 及更早版本。 我特别指出我们希望继续支持 IE11——我认为它约占我们流量的 3%,这比我们认为它太旧的 1% 截止值要高得多。

关于过程。 这种“问题”不是 RFC 流程的设计目的吗?

当事情更加充实时,我们将发布 RFC。 其中很多都需要探索、实验和实际测试,以确定我们能做什么和不能做什么,以及我们可以使用哪些迁移策略。 我们现在没有足够的细节来开始考虑 RFC(应该包括一个全面的迁移策略)。

好的,谢谢你的澄清!

@gaearon

我们将完全摆脱合成事件是合理的。

如果event.currentTarget指向附加了事件侦听器的元素,这将如何工作,这在本机情况下总是意味着document - 或者一旦 React 切换到 React 根?

React 不仅仅是设置属性

(...)

我的观点是,React 在内部使用属性还是属性是一个实现细节

当它可以影响 DOM 中发生的事情时,为什么这是一个实现细节? 除非这仅涉及以某种方式反映在属性(和返回)中的属性,例如class / className

我觉得对class / className处理的混淆与 React 是否使用属性或属性被视为实现细节这一事实有关。 我有 Angular 背景,当我开始使用 React 时,这对我来说是最大的问题——在 Angular 中,属性、属性和事件处理程序之间的分离直接从语法上很清楚,我很困惑 DOM 元素上的 props 是否由 React 设置为属性或属性。

这将如何与 event.currentTarget 指向附加事件侦听器的元素一起工作,这在本机情况下总是意味着文档 - 或者一旦 React 切换到 React 根?

我还不知道。 :-) 我们会看看我们能做些什么。 其中一些事情完全有可能不会奏效,或者会以不同的方式出现。 该计划只是我们计划研究的事物的粗略轮廓,以及它们的统一愿景。

当它可以影响 DOM 中发生的事情时,为什么这是一个实现细节? 除非这仅涉及以某种方式反映在属性(和返回)中的属性,例如类/类名。

对于他们中的大多数人来说,从用户的角度来看,使用哪一个没有明显的区别。 我认为他们中的大多数都反映了(尽管也许我错了)。

我有 Angular 背景,当我开始使用 React 时,它对我来说是最大的问题——在 Angular 中,属性、属性和事件处理程序之间的分离直接从语法上很清楚,我很困惑 DOM 元素上的 props 是否由 React 设置为属性或属性。

我很欣赏你的观点。 然而,在实践中,这种差异通常与大多数 DOM 元素无关,并且值得商榷的是,学习使用哪个元素的来龙去脉,并且总是必须考虑它,这对于日常产品开发实际上是有价值的。 我认为人们混淆他们的程度说明了它实际上与他们并没有那么相关。

(在某些情况下,它变得更加相关,例如与自定义元素。但即使在那里,同样支持两者也同样令人困惑,因为您必须选择使用哪一个。这已经在其他地方进行了辩论,所以我想避免跳跃再次进入这场辩论——我们收到了来自@robdodson等人的建议,我们将对其进行调查。)

@丹尼尔15
如果没有提到的策略(我认为其他任何地方都没有提到),额外的对象包装器不会以任何方式使其更安全。
我相信用户已通过dangerouslySetInnerHTML充分警告用户注意危险使用。 这就是用户被迫检查文档、考虑影响并做出决定的时候。
将(可能未清理的)字符串包装到对象/函数中的需要不会让他重新考虑或清理包装的值。
如果它可以那样工作,那么也许{ __html }还不够复杂,而[{ _html: { __html }]会使它变得更加安全——我们必须说多少次某事是危险的以使其安全?

凭借您提供的见解,我理解了其中的原因,但我认为它目前不适用于 facebook 以外的任何人,因为我们不知道“ { __html }表示经过清理的 html”规则。
我一直认为这只是 API 中的另一个障碍。 感谢您抽出时间并对此有所了解,现在更有意义了。

这不仅仅是为了让它变得更复杂,而是为了防止未经清理的数据被意外使用。

我只是喜欢社区如此固执己见的反应方式。 感谢你们听到这一切并充分利用它。

我喜欢每个人都认为即将到来的变化或在最后一个版本中出现在 React 中的变化是“破坏性的”。 那些人显然没有体验过 Angular 2 > 3 > 4 次。

我喜欢这些变化。 就我个人而言,我不介意className和解构class可能会变得很麻烦。 但我很想看看你们会想出什么。

我想要求继续讨论这个话题。 您是否发现污染危险的 HTML 有用与否很有趣,但与问题无关。

我喜欢反应

这是一个绝佳的机会,可以帮助刚做出反应的开发人员感到更受欢迎。 我很高兴这正在发生。

只是让人们使用类没有负面影响,除了它不适用于解构和迁移成本。

@gaearon投入 2c,但这两个负面因素似乎与当前负面因素一样大或更大(学习类的一次性小成本 => 类名与始终避免解构 + 生态系统级迁移成本)。

反应:心:

在上面呼应@natew

@gaearon投入 2c,但这两个负面因素似乎与当前负面因素一样大或更大(学习类的一次性小成本 => 类名与始终避免解构 + 生态系统级迁移成本)。

无论如何,从className更改为class背后的动机是什么?
据我所知,您的评论归结为两个论点,(如果我错了,请纠正我):

在概念上更接近大多数人的期望

好的,但添加Name是最小的障碍。 学习使用className是学习 React 最简单的部分。 这是一个没有缺点的小怪癖 - 实际上它实际上解决了四个字符的问题。 而且它的认知开销比提供的任何解构替代方案都要少。
想象一下,教某人如何设计他们的第一个 React 组件

function Button({ color, ...rest }) {
  const buttonClass = rest.class +  ' Button-' + color;
  return <button {...rest} class={buttonClass} />
}

我的菜鸟头会爆炸。
我认为在与 API 交互时,人们希望 API 能够提供解决方案。 ClassName 是一个内置的解决方案。 类是一个内置问题。

少打字

Bruh,它是四个字符 8^) 。 此外,即使我们解构class的频率远低于我们目前使用className的频率,但我们这样做时的打字次数也更多。 所以我会少输入 4 个字符 12 次,但每次我 desctructure class时又增加了 50 个字符? 这很愚蠢。

我错过了这种变化还有另一个令人信服的理由吗?
动机是否与 DOM 属性/属性的一致性有关?
对我来说,这似乎太学术了。 大多数人都不太了解这些实现细节,我认为他们不需要。

是不是如果今天发布 React 将允许class而不是更改为 className?
我认为这无关紧要。
React 今天不是开源的,如果它是/将在未来一年开源,那么届时可能会做出不同的决定。
有时,坚持一致性比试图消除每一个皱纹更好。

如果 React 从一开始就使用 class,我们会习惯于解构 class 并将其重新分配给 className,但是任何有 PR 来更改 class _to_ className 的人都会被称为救世主。

最后,我只想说我没想到自己会为此如​​此激动,所以如果有任何粗鲁、侮辱或指责的内容,我深表歉意。 我感谢你在 React 上所做的所有工作,感谢你在 Twitter 上提供的所有知识——我用你的推文来捍卫我在采访中给出的一些答案。

我向dan.church祈祷你改变主意。

很高兴react能不断升级,作为一个使用react的开发者,不希望看到它被vue赶超。 但是className->class的过程一定很痛苦。

我不反对className -> class为了复制粘贴而重命名,但目前还没有明确的动机。 className存在于 DOM 中,而保留的道具名称不知从何而来,例如htmlFor 。 我觉得在重命名时应该优先考虑这些,并且这可能不那么普遍,也可以作为测试。

@sonhanguyen htmlFor 也是官方 Web api 名称: https ://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/htmlFor

@allan2coder不是将其包装在数组中,而是将其包装在<React.Fragment><>中。

@allan2coder另外,请让我们保持这个主题,如果您愿意,可以通过提交单独的问题来提问。

我想提请注意patch-package ,它是一个可以很容易地修补您的依赖项的软件包(例如,使它们停止使用不受支持的React API)。 诚然,这对于应用程序代码比库代码更有用,但我认为它应该有助于解决@philipwhiuk的一些担忧。

我很期待。

  • 从 onChange 迁移到 onInput 并且不要为不受控制的组件填充它。

对于上面的话,我很好奇 onChange 事件会在接近原生事件的情况下使用还是将来不使用?

@穆云云

根据措辞,他们不打算保留 onChange 的当前行为。 这没有多大意义。 像其他现代库一样 React 不会是浏览器兼容层,也不应该是。

当前的 onChange 模拟 onput + 其他一些情况。 考虑到 DOM 中已经存在更改事件并且它没有相同的语义,这根本没有意义: https ://developer.mozilla.org/en-US/docs/Web/Events/change

@jxub

有点离谱,但令人遗憾的是,没有人(据我所知)有想法制作一个 html/css/svg -> jsx 转换器,以便通过许多微不足道的更改来轻松迁移到 React,以将 HTML 属性映射到反应道具。 这么多工时浪费在执行主要是查找和替换:(

我不了解其他编辑器,但是当您将 HTML 代码粘贴到 JS 时,IntelliJ IDEA(以及 WebStorm、PhpStorm 等)会进行这种转换。

有点离谱,但令人遗憾的是,没有人(据我所知)有想法制作一个 html/css/svg -> jsx 转换器,以便通过许多微不足道的更改来轻松迁移到 React,以将 HTML 属性映射到反应道具。 这么多工时浪费在执行主要是查找和替换:(

它确实存在,但它很旧并且不完全正确: https ://magic.reactjs.net/htmltojsx.htm

我们应该重振这种努力。 如果您想提供帮助,请执行以下操作: https://github.com/reactjs/reactjs.org/issues/484。 到目前为止,没有人愿意提供帮助并跟进。

它确实存在,但它很旧并且不完全正确: https ://magic.reactjs.net/htmltojsx.htm

我以前用过很多次——在将某些组件外包给懂 HTML/CSS 但不懂 JavaScript 的人时使用它是很常见的。

因此,只需提供反馈,即这是人们在实践中使用的有用工具。 网上也有其他转换器。

这种方法的一个问题是它只是单向的(仅迁移_to_react)。 不过,这个问题对于 React 来说并不特别。

希望它会让事情变得更容易......

这种方法的一个问题是它只是单向的(仅迁移以做出反应)。 不过,这个问题对于 React 来说并不特别。

为什么? 反过来它应该更容易 - 只需运行ReactDOMServer.renderToString

耐心等待发布

@gaearon

为什么? 相反,它应该更容易——只需运行 ReactDOMServer.renderToString。

好的,所以对于上下文,讨论的问题是:我希望编写 html/css 并且对 JavaScript 不太了解的人能够处理 JS 代码,以便能够处理组件的标记/样式/布局。

现在做到这一点的一种方法是让他们在 html/css 中开发它并使用 htmltojsx。 这对我来说效果很好。

问题是我现在必须自己在 React 中维护每个标记/样式/布局更改。

如果我调用ReactDOMServer.renderToString确实会得到静态 HTML,但该 HTML 会丢失所有实际的组件代码,因此将其提供给 UI 人员并使用他们的输出是不可行的,因为我必须重写所有我的逻辑。

像 react-sketchapp 这样的东西是一个很好的解决问题的方法,但我希望有一种更通用的方法让我在使用常规 html/css 时做到这一点。 例如 - 通过某种形式的元数据并在元素上保留反应 ID。

我完全明白这不在 ReactDOM 核心的范围内,但它肯定在它的领域内,并且是一个有趣的问题。

这不是高优先级 - 我主要只是想解释为什么 htmltojsx 对我们中的一些人有用,即使在迁移的上下文之外:)

我希望编写 html/css 并且对 JavaScript 不太了解以处理 JS 代码的人能够处理组件的标记/样式/布局。

这是一个多大的问题,教他们一点 JSX 会有多难? 无论如何,这些更改都需要由精通 React 的工程师进行审查。

对不起,如果这太离题了,但我相信现在只有 HTML/CSS 是不够的。

@gaearon如果它变得嘈杂,可以随意隐藏它,因为它是对上述已经轻微的 OT 评论的回复)

这是一个多大的问题,教他们一点 JSX 会有多难? 无论如何,这些更改都需要由精通 React 的工程师进行审查。

好吧,它需要以下内容:

  • 仅与熟悉您当前的 React 堆栈的承包商合作。 很难找到会学习样式组件的人
  • 安装 Node (npm)、你的堆栈(React、webpack 等),以及在每个 UI 人员的计算机上运行它所需的一切项目并使其保持最新。
  • 教他们一些基本的编程和 JavaScript,学习如何使用开发工具,控制台错误等。
  • 教他们 React,它的语法是什么,诸如className之类的东西, key的含义等等。
  • 只与愿意以这种方式工作而不是制作 HTML/CSS 的承包商和自由职业者合作。 这通常也会使事情变得更加昂贵。

现在,就像上面提到的那样,react-skeptchapp 之类的东西是一种有用的方法,可以让 UI 人员更容易上手——但它仍然需要他们学习很多东西。

我完全明白你为什么要问这个问题,我不确定这是一个常见问题(我怀疑它是)。 无论如何,我认为它不在 ReactDOM 核心的未来范围内。

这完全是题外话 :-) 让我们在 Twitter 或其他地方继续这个讨论。

“您看到工具用于的行为是工具鼓励的行为”
~ 加里·伯恩哈特

React 的使用方式,因为其中大部分不是 React API 的一部分,导致了大量的陷阱,导致像这样的讨论,每个人都感到困惑和沮丧。 是否因为 javascript、html 或自身反应而使用class之类的保留关键字?

回到 16.3 中所做的更改(如果我没记错的话),通过接受传递给由 vdom 呈现的本机 html 元素的任何属性,库现在的行为会有所不同,我清楚地记得我的大部分代码库现在都受到错误的困扰,因为我们实施这种明显不好的模式的行为

<div {...this.props} />

所以我得说我很失望丹建议我们继续在所有代码库中传播这个糟糕的代码。

首先,在props的内容中没有任何保证,但是如果您将错误的 props 传递给原生 html 元素,那么第一次几乎总是不会做他们所期望的事情,但同时将父道具传播到子组件被认为是安全的,但实际上这非常懒惰

<Child {...props} />

const Child = (props) => <div {...props} />

有时你甚至不知道你在渲染什么,这个问题变得更加难以处理。 使用类型系统对这类组件进行类型检查也非常困难,因为这意味着大多数组件都需要实现一些它们应该在彼此之间共享的随机接口,这是一个很深的兔子洞。

如果对 react 进行重写以解决此问题,我希望其背后的设计者能够意识到这些不良模式对代码库造成的危害,而不是加倍做出错误的决定。

我们必须记住,jsx 是建立在 javascript 之上的,并且以 javascript 的“特质”为借口,在使用关键字时故意与语言发生冲突是修复 API 的糟糕的第一步,我建议不要开始战争反对你会完全远离它的语言

@gaearon 好久不见! :)(ps。对不起tl;前面的博士)

无论如何,我只是想深入了解一下我从自己的冒险中学到的东西。 我已经制作了自己的“最简单”的 React 衍生产品,现在我将其用于性能/功能关键应用程序。 这最初只是一个有趣的实验,但在实际情况下,我看到初始渲染/更新/删除的性能提升超过 300%,包括许多其他好处。 这也没有使用池事件处理程序。

IIRC 其中很大一部分来自我自己的库,绕过了所有 React-props 逻辑,简单地将属性直接输入 setAttribute,将样式直接输入到 style.setProperty,将侦听器直接输入到 addEventListener,等等。 所以基本的 DOM 元素接口看起来像这样 `{attributes: {}, style: {}, listeners: {}, className: "", ...},它更冗长但接口现在很小且易于实现和非常快。 这对你来说可能太极端了,但它对我很有帮助。

我一直在做的事情是完全放弃 CSS,所有样式都是内联的。 它比您预期的要快得多,并带来了许多不错的实际好处,它还回避了浏览器初始 CSS 解析(这非常昂贵)和选择器匹配的成本,从而弥补了大部分开销。 即使是复杂的层次结构(没有任何树修剪),我也可以在功率不足的笔记本电脑上轻松实现稳定的 60 FPS 甚至更高。

我想其中大部分内容对您来说并不是真正有用的,但也许那里有一些有趣的东西。 无论如何,我对 HTML+React 的主要抱怨是 React 用户组件在不借助 CSS 的情况下不会公开任何用于布局/定位的界面(并且可能在某种程度上还包括事件)。 简单地说,如果我创建一个 ButtonComponent 然后使用它,默认情况下它不能定位或集成到布局中; 在其中实现特定用途的逻辑,将其包装在一个可以定位的虚拟元素中,或者通过公开一个合并到用于 ButtonComponent 根元素的样式中的样式道具。 这些都不是完美的,并且按原样合并样式是危险的,因为很容易将不应该的样式放入其中。 本质上,问题在于在组件边界处,可用属性的子集应该是公共的(定位/布局)和一些内部的(视觉样式)。

我做的另一件事是组件和内容/子项之间的分离。 例如,DOM 组件不采用子列表,而是接受内容实例。 内容实例实现了子节点的协调逻辑和渲染,这意味着您可以针对不同的目的有不同的实现。 最明显的用例是; 主要是静态层次结构与动态生成的孩子。 因此,构成大多数的静态层次结构可以使用更快更简单的逻辑来实现,而动态生成的子级可能具有可配置的策略。 它还开启了拥有“内容组件”的可能性,这些组件可用于智能管理例如弹性盒布局,而无需不必要的间接。

与此相关,我认为 React 出错的是孩子,我还没有得出具体的结论或解决方案。 但我坚信 React 存在一个基本问题,即如果不重新渲染这两个点之间的每个元素,就不能将 props 从根部冒泡到层次结构中的任意点,并且有效地修剪通常也是有问题的。 性能大多“足够好”,而在 React 中管理它所增加的复杂性可能不值得解决。 但是到目前为止,在我的实验中,我已经能够使用非常少量的琐碎代码将完整的根更新成本降低到仅几分之一,但我的直觉表明它与 React 的哲学或其简单的子模型不太兼容。

绝对不适合你的东西,但我的库的一个重要特性是它基本上只提供了一个用于通用目的的最小的“基本 DOM 元素”。 这个想法是,如果您正在开发一个具有特定要求/情况的大型项目并且非常便宜并且不诉诸“黑客”,例如如果您非常接触,那么您可以轻松扩展/替换和实现您自己的低级特定行为面向,想要做特殊的样式处理等。这也意味着不同的版本是兼容的,只要ABI相同就可以并行运行(更改应该非常罕见并且非常容易修复)。 这也意味着你可以在 DOM 元素界面上颇有主见,而不必包罗万象,试图解决每个人的问题。

无论如何,也许大部分只是漫无边际,我可能没有很好地传达大多数概念,但也许有一些有趣的信息来自相反方向的人。 其中大部分可能与您无关,仅仅是因为您的目标是“简单”,但谁知道:)

同样在我忘记之前,您可能会对我的objectKeyValueReconcile函数感兴趣,该函数经过专门优化,可以非常快速地比较类似 React 场景的 prev/next 道具。 对我来说,这是一个相当重要的现实世界性能提升的原因。

https://github.com/syranide/surgical/blob/master/packages/surgical/private/objectKeyValueReconcile.js

恕我直言,我会放弃“班级”的想法。 JSX 最终会消亡。

向 React DOM 添加对基于非元素的 DOM/窗口事件的支持是什么想法? 随着可能删除合成事件,我怀疑仍然会有某种形式的事件收集/更新/批处理。 按键、调整大小和窗口滚动事件是我想到的常见场景,但可能能够支持https://developer.mozilla.org/en-US/docs/Web/Events中的大多数/所有列表在相同的抽象后面是有益的。

这恰好也在最古老的未决问题#285 中讨论过😄。

@gaearon

className -> class的实际效果将是:

({ className }) => <div className={className} />

会变成

({ ...rest }) => <div class={rest.class} />

这种变化会带来相当多的痛苦,而好处则完全是学术性的。 我们已经看到其他社区做类似的事情 - 例如,考虑到python3是十年前首次发布的,我们仍在争论它。 社区中相当大的一部分人没有进行过渡,也永远不会。 请重新考虑。

@kans

或这个:

props => <div class={props.class} />

这与原始功能具有相似的复杂性。

我喜欢 className,因为 class 是 js 中的一个关键字,但无论哪种方式都不要认为这有什么大不了的。 我更喜欢有魅力的造型,所以,这不会影响我。 在过去的几年里,我可能已经用了几十次 className 了?? 几乎从不。

尽管我想到了一个支持class的想法,但实际上大多数使用 className 的人都在使用 css,并且他们期望class的 html/css 模型。 这个道具的压倒性主要目的实际上只是与 css 代码链接,对,那么为什么不像 html/css 用户期望的那样将其称为类呢?

IMO 在设计系统代码之外,真正惯用的 React 开发通常不会使用 className 或 class 。 当我确实需要为 css 使用类时,它主要被隔离到一些小的 UI 组件中。 应用层使用的几乎所有东西都是更高级别的(比如, <Columns verticalAlign="center"><BodyText /> )。

所以我想我想知道从className重命名为class是否会让那些使用道具的人更容易(更容易进入 React 开发,切换上下文,不生气等),为什么不直接重命名呢?

请减小捆绑包大小。

由于这是一个重大的重大更新,也许我们也可以修复 React 生命周期命名!

shouldComponentUpdate => shouldUpdate等。这个命名是愚蠢的。

@AlexGalays

由于这是一个重大的重大更新,也许我们也可以修复 React 生命周期命名!

即 shouldComponentUpdate => shouldUpdate 等。这个命名太傻了。

搜索时,较长的生命周期挂钩名称不那么模棱两可。 较短的名称过于通用,并且取决于它们所在的上下文,因此可能会巧合地匹配其他大型代码库(误报匹配)。

生命周期方法是 React 核心的一部分,这个问题完全是关于 react-dom。

@ljharb
哎呀,确实!

@sompylasar
抱歉,这根本不是一个好的理由(双关语,reasonReact 修复了方法名称 :))。 我们也不用它们的包名作为我们所有模块的前缀,我们发现它们很好。 无论如何,将停止谈论这个,因为 react-core 超出了这个问题的范围。

很想看到这些变化。
我希望它们将在考虑到自定义元素互操作的情况下实现。

我想知道是否值得将一些讨论转移到论坛中的单独线程(https://discuss.reactjs.org)? 由于 GitHub 问题不像论坛帖子那样进行线程化,因此在同一个问题中讨论多个不同的事情变得很棘手。

className -> class的变化对我来说似乎很有趣😺

观看,2019 年 React 项目

const {
  class: className, // YouKnowIamRight PepeHands
  someFancyProp,
  ...restProps
} = props

我肯定会看到这一点。

我非常喜欢能够复制粘贴 HTML 而不必更改className但同时我看到了class保留关键字可能带来的问题。

在这一点上,我宁愿坚持使用className ,除非你对它有强烈的工程关注(不是个人偏好)

但这只是我的务实意见。

虽然我理解无法破坏class标识符的额外摩擦,但我觉得这个线程中有太多人高估了他们需要接收类名作为道具的次数。

className传递给 React 组件(不仅仅是 DOM 元素)意味着您要么在不提供任何新抽象的情况下制作非常小的构建块,要么该组件公开其一些实现细节。 在第一种情况下(例如<Button />组件),您可能希望遵循@gaearon的示例并将道具的“其余”也转发到 DOM 元素。 在第二种情况下,也许额外的摩擦会迫使你避免做这件事并想出更好的解决方案。

根据我的卑微经验,我不得不将粘贴 HTML 复制到 JSX(并将class替换为className )的次数比我记得制作接收className的组件的次数还要多。

将所有道具传播到 HTML 是一种反模式。 如果将来有人包含一个恰好与 HTML 属性匹配的额外道具,它将意外地改变行为。 如果 IE 添加了一个新属性,你会被淹没。

@philipwhiuk如果你只传播你不使用的道具,就不会有任何行为问题。

@j-f1

如果你只传播你不使用的道具,就不会有任何行为问题。

并不真地。 如果您向组件 API 添加新选项,则此选项将停止传递到底层 DOM 节点。 有人可能依赖于在元素上设置的确切属性,然后你破坏了那个人。 将所有未使用的道具传播到下面的任何东西意味着对组件 API 的任何添加都是一项重大更改。

顺便说一句,我使用了一个随机示例,您在其中解构了class的值,但不要切断该细节。

你们中的许多人(是的,确实如此)从propsstate中解构几乎每个值,而不是出于非原因使用点符号,而不是避免键入一些额外的文本。

所以这就是为什么我要强调这种情况,但不要侧身而专注于传播道具或任何你可以谈论的其他话题。

如果您更务实一点,您会谈论技术含义而不是您的个人偏好,但我没有看到有人谈论className的技术含义。

您需要注意的另一件事是,您让核心贡献者专注于个人喜好问题(证明我错了,只是因为我希望您务实地考虑它)

他们的时间、精力和金钱(来自公司)是有限的,如果社区明白有更好的事情需要我们关注,并且核心团队中的任何人愿意花一个小时在我们更喜欢他们使用的事情上React 的下一件大事,没有针对这种变化的重构代码。

但同样,我的务实意见。

说到 polyfill,我认为 react 不应该尝试检测用户是否指定了“好”的 polyfill。
(例如代码中的hasBadMapPolyfill
React 不应该为编程项目中可能犯的所有随机错误负责。

@AlexGalays React 依赖于使用具有正确语义的 Map 实现。 如果用户使用不兼容的 polyfill,他们的应用程序可能会以意想不到和令人困惑的方式中断,因此在这种情况下提前警告很有帮助。

这也仅在开发构建中完成,因此在生产中没有开销。

我喜欢这个 React Fire,你会继续努力,因为这似乎是使 ReactDOM 现代化的更有趣的一步。

反应火是否有可能不重新绑定事件处理程序?

class Compo exntends Compoent {
 onClick() {
   ...
 }
  render() {
   <button onClick={this.onClick} >click me </button>
  }
}

我认为没有人真正希望事件处理程序被反弹。 在极少数情况下,您可以手动绑定它

@cullophid

反应火是否有可能不重新绑定事件处理程序?

您可以使用箭头函数自动绑定或在构造函数中绑定函数一次将方法绑定到类。 如果您想要链接到事件的唯一参数,您可以查看记忆事件处理程序或将 DOM 属性附加到节点本身并通过event.currentTarget访问它们。

class Compo extends Compoent {
 onClick = () => {
   ...
 }
 render() {
   <button onClick={this.onClick}>click me</button>
 }
}

简化事件系统的另一个好处(我们可以回到原始 DOM 事件而不像所有框架那样进行任何池化吗?:))是静态类型也更容易。

似乎是一个很棒的计划! 拥有 IE 11 支持真是太好了(即使这意味着交付我们自己的 polyfill,这完全没问题)。 作为与政府客户合作的人,他们何时停止使用 IE 11 是完全未知的:(

@MatthewHerbst同一条船,我们的客户确实使用 IE 11,我们有足够的流量😢

只是想插话说这一切都非常令人兴奋。 我读到的让我担心的一件事是:

我们可能不会尝试消除一些现有的浏览器差异

现在我很高兴知道 React 的事件系统将在任何 React 支持的浏览器上“正常工作”。 恐怕这种变化将意味着解决跨浏览器问题将成为应用程序的责任。 这可能会引入很多难以追踪的错误。 ...至少它适用于我的应用程序。 :)

无论如何,一如既往地感谢伟大的图书馆。

@kentcdodds提到JSX 2.0集成是一个可能的想法,我正在阅读该策略,但没有看到任何与此相关的内容。 我想知道这是否只是悬而未决还是将来会推迟?

让IE死吧! 不支持绝对过时的浏览器。 即使是限制性公司,也没有理由不切换到最新的浏览器。 您将在统计数据中看到 IE11,直到您和网络停止支持它。

@hbroer旧版软件?

@hbroer没有人停留在旧版浏览器上,因为他们的网站仍然可以运行,他们这样做是因为他们别无选择,或者不知道如何更新。 为这些用户破坏网站是非常敌对的,并且不会让他们使用更新的浏览器,而是什么都没有。

  • “不知道如何更新” - 不是我们的问题,但我们可以在“安装新浏览器”的消息中添加浏览器列表,也许还有帮助文本和 Microsoft 热线的电话号码 ^^
  • “别无选择” - 对,但组织必须更新他们的环境。 如果他们的工具不起作用,他们会的。

我讨厌为过去编写代码并且不能利用新技术的好处,因为 90% 的程序员仍然支持生活在上个世纪的底层 15% 消费者的蹩脚浏览器。 ^^ 不想在接下来的 10 年里再次出现这种“哦,这个 Internet Explorer 6 书呆子怎么了,我们必须支持那 15%”。

顺便说一句,M$ 接缝为 Windows 7 和 8 带来 Edge,并切换到 webkit。

@hbroer如果影响用户,一切都是我们的问题。 对其他人有一些同理心。

(另外, M$是一个非常年轻且非常过时的 90 年代后期参考,您可能希望删除它;如果您这样做,我很乐意将其删除)

我明白了,这里有很多 M$ fanboiz。 :DI 真的关心人类,但不关心阻碍技术进步的组织,或者那些打算多年来必须支持这种旧废话的程序员。 我对使库“旧垃圾兼容”的附加软件包没有问题。 但是 2019 年的图书馆应该在编码时考虑 >=2019 技术,而不是 <=2013 技术。 不得不支持(哦,让我们以另一种方式做这件事)野生动物园和(旧的)边缘废话已经够糟糕了。

微滴

@hbroer事实上,古老的安卓浏览器和古老的 safari 比任何微软浏览器都更成问题。 这不是要成为“fanboi”而是要专业,而使用“ M $”一词则不是。

不,以任何方式支持旧技术都不是“坏事”,这是道德和道德的事情。 糟糕的是那些“在 X 中工作得最好”的网站,无论是 Netscape Navigator、IE 6 还是最新的 Chrome。

我明白了,这里有很多 M$ fanboiz。

@hbroer我在这里看到一个人进行全面人身攻击。

但是 2019 年的图书馆应该在编码时考虑 >=2019 技术,而不是 <=2013 技术。

不,不应该。

如果您花一秒钟时间查看浏览器列表的默认设置,您会感到惊讶。 相反,你诉诸人身攻击和学校食堂级别的侮辱。

一旦你获得了足够多的用户,IE11 就会成为访问你网站的一大群人。 在之前的工作中,我们每月有近 100 万人通过 IE11 访问我们的网站。

browsers

如果你想支持旧垃圾添加多边形填充。 没有理由不为未来和现在编写代码。 支持旧技术会使网络应用程序变得比需要的更胖、更慢。

Ps 我看到一个看不懂讽刺和不在乎表情的人^^

@hbroer您正在展示 IE11 的存在,因此我们应该为此进行编码。

而且,再一次。 请参阅https://browserl.ist中的默认值。

Ps 我看到一个看不懂讽刺和不在乎表情的人^^

是的,没有。 这是巨魔和操场恶霸常用的策略。 “什么?!我没有侮辱你!这只是一个笑话!”。

地球上 0.20% 的人,即使被“使用互联网的人”过滤,也就是 640 万人。 百分比完全无关紧要。 人类代码; 过去和未来,以及你的捆绑包大小,都无关紧要。

如果您想针对人类捆绑大小进行编码,就像浏览器兼容性一样,这当然很重要。 用户不仅希望事情能够正常工作,而且加载速度也应该很快。

现在在 2019 年,我将用于新项目 css 网格(仅在 IE11 上具有实验性支持),并将转换为 ES6,我不想为那个过时的浏览器提供 polyfill。 IE11 用户只会收到一条消息:更新您的浏览器或使用替代方案。

有些人不想使用 java 脚本。 你关心他们吗? 你在统计数据中看不到这些人。 而且我也不在统计数据中,就像许多其他阻止该工具的人一样。

我关注每一个没有过时的浏览器。 由于 Windows 7(支持 2020 年 1 月结束),我支持 edge,它的用户比 IE11 废话少,而且现代人使用现代浏览器。 ^^

没有人阻止你使用 polyfill 和类似兼容性包的东西。 但是核心应该是最新的,而不是仅仅因为一个旧的 M$ 技术浏览器而落后。

我在许多 javascript 框架中缺少的是 LTS。 这就是我们可以谈论的。 如果您构建具有当前功能的现代页面,那么使用最新的技术框架会很好。 如果你正在为需要最大稳定性和兼容性的 b2b 东西构建 webapp,那么你可以使用 LTS 版本。 或者使用淘汰赛。 那么你可以支持少数 100 吨仍在使用未更新的带有 IE6 的 Windows XP 的人 ^^

兼容性在原始帖子的“权衡”下明确列出,因此对旧浏览器的完美支持已经是次要关注点。

如果您需要支持它们,它们将需要更多的 polyfills 和集成,但这将是您的选择。 您还可以为不同的浏览器目标创建多个捆绑包,并为每个访问者提供尽可能小的 JS,这样它就不会影响您的整个受众。

React Fire 本身的进展似乎没有受到影响,所以从这场辩论中真的没有任何收获。 让我们继续前进,回到主题。

这是解决#6410 的好机会吗? 它似乎与对onChange / onInput的拟议更改的影响相似。

2019 年 6 月 5 日更新

有一阵子了。 这是关于我们所处位置的一个小更新。

我们在 12 月开始研究 Fire。 https://github.com/facebook/react/pull/14382和其他线程中有一些正在进行的工作。 然而,当我们开始删除我们认为不必要或过时的部分事件系统时,我们发现了许多非常有用的边缘情况并防止了错误——即使在现代浏览器中也是如此。 我们仍然希望减少遗留的臃肿,但尚不清楚更接近原始 DOM 事件是否是实践中的最佳方向。 减少库代码只是在应用程序代码中重新添加几次并不是最好的权衡。 甚至不可能在应用程序级别修复它。

另外,在开发 FB5时,我们意识到即使在使用 React 时,今天在实现在鼠标和触摸设备上都可以工作和感觉良好的用户界面方面存在很大困难。 当您使用诸如onClick之类的事件时,即使是按钮之类的基本操作在鼠标和触摸上的感觉也非常不同,并且通过悬停、聚焦等实现一致的行为变得更加困难。

因此,当我们开始研究 Fire 时,我们认为自定义事件系统可能是不必要的。 但是在原型化移除它之后,我们意识到我们的事件系统实际上是我们解决这组问题的最大杠杆

由于这次调查,我们暂时暂停了 React Fire 中其他项目的工作,并决定首先只关注事件系统。 该项目被称为 React Flare (https://github.com/facebook/react/issues/15257)。 它本身就具有足够的挑战性,并且会影响此列表中的其他项目,因此我们首先单独关注它。

React Flare 的目标是轻松构建在桌面和移动设备上感觉很棒的 UI,使用鼠标和触摸,并且可以访问。 它包括用于管理诸如 Press、Hover 和 Focus 等交互的声明性 API。 与当前的 React 事件系统不同,Flare 设计不会为你不使用的事件扩展包——它应该允许减少 UI 库中处理鼠标和触摸事件的代码量。

React Flare 仍然是一个实验,但我们对它的整体方向相当有信心,并计划最终使其以开源形式正式可用。 (目前它只有在您手动从 master 构建时才有效,并且由于我们正在积极研究它,因此无法保证 semver。)与 Fire 一样,“Flare”只是一个代号——当我们发布它时,它将会有正确的命名、文档等。也许是react/events或类似的东西。 我们最终也希望在 React Native 中提供等效的事件。

在我们完成了 React Flare 的初始实现之后,我们将回到 React Fire 列表并使用我们从中学到的东西重新评估所有其他点。 如果 Flare 接管一组“更丰富”的事件,我们仍然有可能简化 React DOM 中的“基本”事件处理并删除一堆 polyfill。 感谢大家到目前为止的讨论,我希望这是有用的。

做得好! 所以事件系统仍然需要平衡鼠标和触摸事件,但它将是轻量级的并且独立于 React。

“React Flare”会作为默认 React 包的一部分出现,还是需要额外安装考虑到它将附带的 API 数量?

我们希望避免捆绑未使用的代码。 因此,目前的意图是让每个 API 都可以选择加入。 也许在一个包中单独的入口点。

这个鼠标和触摸事件系统会利用PointerEvent吗? 在之前的更新中我没有看到提到这个网络标准,所以我只是想提请你注意。

指针事件是为指针设备触发的 DOM 事件。 它们旨在创建单个 DOM 事件模型来处理指针输入设备,例如鼠标、笔/触笔或触摸(例如一根或多根手指)。 指针是一种与硬件无关的设备,可以针对一组特定的屏幕坐标。 拥有一个用于指针的单一事件模型可以简化网站和应用程序的创建,并提供良好的用户体验,而不管用户的硬件如何。

这里是当前浏览器兼容性的直接链接。

@jonathantneal是的,新系统大量使用指针事件——当不支持指针事件时,会回退到鼠标/触摸事件。

请在重新设计事件系统时考虑影子根 - 仅附加到 React 根并不能解决当今的大多数问题,只能附加到元素(https://github.com/facebook/react/issues/9242, https:// github.com/facebook/react/issues/15759, https://github.com/facebook/react/issues/13713, https://github.com/facebook/react/issues/11827)

在此更新中: https ://github.com/facebook/react/issues/13525#issuecomment -499196939 @gaearon提到:

然而,当我们开始删除我们认为不必要或过时的部分事件系统时,我们发现了许多非常有用的边缘情况并防止了错误——即使在现代浏览器中也是如此。

我很好奇这些边缘案例的列表是否记录在任何地方?

@gaearon现在Flare 已经熄灭(SCNR),是否有更新计划(关于2019 年 6 月 5 日更新)如何进行?

@trusktr一样,我也想在这里解决#11347。

可以将 polyfill 拆分为另一个包,尤其是与主要常青浏览器无关的包。

大家好,已经有一段时间了,我们已经断断续续地尝试了其中的一些东西。

让我对每一个进行更新:

我们仍然想这样做,但我们决定“保留” React 17 以尽可能减少可能的重大更改,以便它可以专注于此列表中的下一个项目。 所以这个改变要等到 React 18。

  • 在 React 根目录而不是文档中附加事件 (https://github.com/facebook/react/issues/2043)。 将 React 应用程序嵌入到更大的系统中时,将事件处理程序附加到文档成为一个问题。 Atom 编辑器是最早遇到此问题的案例之一。 任何大型网站最终也会开发出与stopPropagation与非 React 代码或跨 React 根交互相关的非常复杂的边缘案例(https://github.com/facebook/react/issues/8693、https://github .com/facebook/react/pull/8117,https://github.com/facebook/react/issues/12518)。 我们还希望将事件急切地附加到每个根,以便我们可以在更新期间进行更少的运行时检查。

我们在 React 17 中这样做。结果证明这是一项巨大的工作,但幸运的是它已经完成了。

  • onChange迁移到onInput并且不要为不受控制的组件填充它(https://github.com/facebook/react/issues/9657)。 有关详细计划,请参阅链接问题。 令人困惑的是,React 对 DOM 中的input事件使用了不同的事件名称。 虽然我们通常会避免在没有显着好处的情况下进行这样的大更改,但在这种情况下,我们希望更改行为以消除一些仅在改变受控输入等边缘情况下才需要的复杂性。 因此,将这两个更改一起进行是有意义的,并以此为契机使onInputonChange完全按照 DOM 事件对不受控制的组件所做的工作。

我们可能会回到这一点,但目前还不清楚有多少流失值得在这里做。 所以这仍然是待定。

  • 大大简化事件系统(https://github.com/facebook/react/issues/4751)。 当前的事件系统自 2013 年首次实现以来几乎没有改变。它在 React DOM 和 React Native 中被重用,因此它是不必要的抽象。 它提供的许多 polyfills 对于现代浏览器来说是不必要的,其中一些产生的问题比它们解决的问题还要多。 它还占 React DOM 包大小的很大一部分。 我们在这里没有一个非常具体的计划,但我们可能会完全分叉事件系统,然后看看如果我们更接近 DOM 给我们的东西,我们能做到什么程度。 我们将完全摆脱合成事件是合理的。 我们应该停止冒泡事件,例如在 DOM 中不会冒泡且没有充分理由冒泡的媒体事件。 我们希望保留一些特定于 React 的功能,例如通过门户冒泡,但我们将尝试通过更简单的方式来做到这一点(例如重新调度事件)。 被动事件可能是其中的一部分。

我们在 2019 年初尝试过这个,真正的最小事件系统在我们的内部测试中效果不佳。 React 正在做相当多的跨浏览器规范化,这对于使用旧浏览器的人仍然有用,或者在更小众的领域,如使用contentEditable的富文本输入编辑器。 也就是说,作为我们将事件附加到根的工作的一部分,我们已经从事件系统中删除了很多抽象,以便将来更容易理解和改进。 作为 React 17 的一部分,我们正在移除造成很多混乱的“事件池”,并且我们也不再冒泡onScroll事件。 我们可能会在 React 18 中停止媒体事件的冒泡,使 React 行为更接近浏览器。 我们确实使用新的事件系统节省了一些字节,但它们被我们正在开发的新功能占用,因此它不会导致包大小整体减小。

  • classNameclass (https://github.com/facebook/react/issues/4331,另见https://github.com/facebook/react/issues/13525#issuecomment- 417818906 下面)。 这已被无数次提出。 我们已经允许在 React 16 中将class向下传递到 DOM 节点。这造成的混乱不值得它试图防止的语法限制。 我们不会单独进行此更改,但将其与上面的所有其他内容结合起来是有意义的。 请注意,我们不能在没有警告的情况下只允许两者,因为这使得组件生态系统很难处理。 每个组件都需要学习正确处理两者,并且存在冲突的风险。 由于许多组件处理className (例如通过附加到它),它太容易出错。

这是提案中最具争议的部分。 从那时起,我们发布了 Hooks,它鼓励编写函数组件。 在函数组件中,我们一般建议对 props 使用解构,但不能写{ class, ... } ,因为这会是语法错误。 因此,总体而言,尚不清楚这是否符合人体工程学,可以真正贯彻执行。 我认为我们将来会重新审视这一点是合理的,或者至少让class不发出警告,让人们做他们想做的事。 但是现在,我们将搁置这个想法。

嗨,这是一篇很棒的文章!
只是想知道是否有任何计划来减少 React-DOM 产品的大小? 对于移动应用程序,这仍然是一种开销,因为浏览器将解析 100+ KB 的 React-DOM JS 和其他模块。 然后是特定于应用程序的 JS。
对于内容丰富的页面,它会导致更大的阻塞和更大的 TTI。

任何想法我们什么时候可以看到这样的变化?

@morevolk-latei 在您的测量中,解析 100 KB 的 ReactDOM 花费了多少时间?

此页面是否有帮助?
0 / 5 - 0 等级