类叶组件中的 connect() 是 React+Redux 中反模式的标志吗?

2024-02-15

目前正在从事 React + Redux 项目。

我也在用归一化 https://github.com/gaearon/normalizr处理数据结构和reselect https://github.com/reactjs/reselect为应用程序组件收集正确的数据。

一切似乎都进展顺利。

我发现自己处于一种类似叶子的组件需要来自商店的数据的情况,因此我需要connect()实现它的组件。

作为一个简化的示例,假设该应用程序是一个书籍编辑系统,有多个用户收集反馈。

Book
    Chapters
        Chapter
            Comments
        Comments
    Comments

在应用程序的不同级别,用户可以贡献内容和/或提供评论。

考虑我正在渲染一个章节,它有内容(和作者)和评论(每个评论都有自己的内容和作者)。

目前我会connect() and reselect基于 ID 的章节内容。

因为数据库是使用 Normalizr 进行规范化的,所以我实际上只获取了章节的基本内容字段以及作者的用户 ID。

为了呈现评论,我将使用一个连接的组件,它可以重新选择链接到该章节的评论,然后单独呈现每个评论组件。

再次强调,因为数据库是使用 Normalizr 进行规范化的,所以我实际上只获得了基本内容和评论作者的用户 ID。

现在,为了渲染像作者徽章这样简单的东西,我需要使用另一个连接的组件从我拥有的用户 ID 中获取用户详细信息(无论是在渲染章节作者时还是针对每个单独的评论作者)。

该组件将是这样简单的:

@connect(
    createSelector(
        (state) => state.entities.get('users'),
        (state,props) => props.id,
        (users,id) => ( { user:users.get(id)})
    )
)
class User extends Component {

    render() {
        const { user } = this.props

        if (!user)
            return null
        return <div className='user'>
                    <Avatar name={`${user.first_name} ${user.last_name}`} size={24} round={true}  />
                </div>

    }
}

User.propTypes = {
    id : PropTypes.string.isRequired
}

export default User

而且看起来效果很好。

我尝试做相反的事情,在更高的级别上对数据进行反规范化,例如章节数据将直接嵌入用户数据,而不仅仅是用户 ID,并将其直接传递给用户 - 但这仅是似乎只是制作了非常复杂的选择器,而且因为我的数据是不可变的,所以它每次都会重新创建对象。

所以,我的问题是,是否有类似叶子的组件(如上面的用户)connect()到商店呈现反图案标志?

我是在做正确的事,还是以错误的方式看待这件事?


我认为你的直觉是正确的。只要 API 有意义,在任何级别(包括叶节点)连接组件都没有问题——也就是说,给定一些 props,您可以推断组件的输出。

智能组件与笨组件的概念有点过时了。相反,最好考虑连接组件与未连接组件。在考虑是否创建连接组件和未连接组件时,需要考虑一些事项。

模块边界

如果您将应用程序划分为较小的模块,通常最好将它们的交互限制在较小的 API 表面。例如,说users and comments位于单独的模块中,那么我想说这对于<Comment>组件使用连接的<User id={comment.userId}/>组件而不是让它自己抓取用户数据。

单一责任原则

承担过多责任的连接组件会产生代码异味。例如,<Comment>组件的职责可以是获取评论数据并呈现它,并以操作调度的形式处理用户交互(与评论)。如果它需要处理抓取用户数据并处理与用户模块的交互,那么它就做得太多了。最好将相关职责委托给另一个连接的组件。

这也称为“脂肪控制器”问题。

表现

通过在顶部有一个大的连接组件来向下传递数据,它实际上会对性能产生负面影响。这是因为每次状态更改都会更新顶级引用,然后每个组件都会重新渲染,并且 React 需要对所有组件执行协调。

Redux 通过假设连接组件是纯组件来优化它们(即,如果 prop 引用相同,则跳过重新渲染)。如果连接叶节点,则状态更改只会重新渲染受影响的叶节点——跳过大量协调。这可以在这里看到:https://github.com/mweststrate/redux-todomvc/blob/master/components/TodoItem.js https://github.com/mweststrate/redux-todomvc/blob/master/components/TodoItem.js

重用和可测试性

我想提到的最后一件事是重用和测试。如果您需要 1)将其连接到状态原子的另一部分,2)直接传递数据(例如我已经有user数据,所以我只想要一个纯粹的渲染)。同样,连接的组件更难测试,因为您需要先设置它们的环境,然后才能渲染它们(例如创建存储,将存储传递给<Provider>, etc.).

通过在有意义的地方导出连接和未连接的组件可以缓解这个问题。

export const Comment = ({ comment }) => (
  <p>
    <User id={comment.userId}/>
   { comment.text }
  </p>
)

export default connect((state, props) => ({
  comment: state.comments[props.id]
}))(Comment)


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

类叶组件中的 connect() 是 React+Redux 中反模式的标志吗? 的相关文章

随机推荐

  • 替换 Fragment 时出现 IllegalStateException

    它是使用兼容性包的小型 Android 2 2 测试应用程序 这是我在收到点击时尝试替换片段的 当然是错误的 方法 我试图用同一 Fragment 类的新 不同 实例替换它 正如我将解释的那样 它无法按预期工作 我需要帮助 public c
  • 两个类里面的代码几乎重复

    此时此刻 我有两节课 UserHibernateDao and TicketHibernateDao import java util List import org springframework orm hibernate3 suppo
  • 如何转义 SQLite FTS 查询的字符串

    我正在尝试使用不受信任的用户输入执行 SQLite FTS 查询 我不想让用户访问查询语法 也就是说他们将无法执行类似的匹配查询foo OR bar AND cats 如果他们尝试使用该字符串进行查询 我想将其解释为更像是foo OR ba
  • Android 网络提供商,需要互联网吗?

    我正在使用网络提供商进行位置更新 我的手机需要联网吗 这是我的代码 LocationMngr LocationManager getSystemService Context LOCATION SERVICE LocationMngr re
  • 使用 pojo 自动完成 primefaces

    我读过一些关于同一组件的质量检查 但我觉得我错过了一些东西 因为我落后了一步 当我使用 primefaces 自动完成组件时 我什至无法打开页面 它的片段是
  • JavaScript 中的 Splat 运算符相当于 Python 中的 *args 和 **kwargs?

    我经常使用 Python 而且我现在正在快速学习 JavaScript 或者我应该说重新学习 所以我想问一下 相当于什么 args and kwargs在 JavaScript 中 ES6 在 JavaScript 中添加了扩展运算符 fu
  • 如何从 CMake 命令行更改 C++ 标准?

    目前我有一个需要 C 17 的项目 因此在CMakeLists txt我很早就有这条线 set CMAKE CXX STANDARD 17 从命令行 cmake 偶尔我想测试该项目是否也可以使用 C 20 进行编译 以避免意外 如何选择从命
  • 我的应用或其依赖项是否违反了 Android 广告 ID 政策?

    我刚刚收到来自 Google Play 的这条消息 但我没有收集广告 ID 警告原因 违反Android广告ID使用 政策和开发者分发协议第 4 8 条 Google Play 要求开发者在以下情况下提供有效的隐私政策 应用程序请求或处理敏
  • 如何在运行时修改 web.config appSettings?

    我对如何在运行时修改 web config appSettings 值感到困惑 例如 我有这个 appSettings 部分
  • 为什么 Haskell 不能正确排序这些 IO 操作?

    我的一个朋友问我为什么要学习 Haskell 为了展示 Haskell 的强大功能 我编写了一个小程序来显示素数列表 main do putStr Enter the number of prime numbers to display n
  • 在 VB.NET 表单之间传递数据

    我有一个带有按钮的表单 单击时会弹出一个对话框表单 在此对话框中 用户需要选择一些数据 完成后单击 确定 按钮 一旦他们单击 确定 按钮 它需要将一个整数返回到之前的形式 我创建了一个对话框表单并尝试通过以下代码调用它 Dim intRes
  • JsTree 与 jquery.validate 冲突

    我有一个 Jstree 填充项目列表 当我单击一个节点时 会使用 ajax 加载部分节点 一切正常 直到我包含 jquery validate 脚本来验证我的表单
  • 无法在 Flutter 中使用 Firebase Auth 进行注册

    我正在为我的应用程序使用 Firebase 我已正确设置所有内容 并且 Firebase Firestore 工作正常 没有任何问题 我能够在那里读取和写入数据 但是当我尝试在 Firebase 中创建用户时 我在调试控制台中收到此消息 I
  • 如何在 nightwatch.js 中使用链接文本单击链接

    假设我的网页上有这些元素 a href dynamic1 One a a href dynamic2 Two a a href dynamic3 Three a 我想点击带有文字的链接Two 如何使用链接文字没有任何独特的属性 如 id 或
  • typescript Symbol.iterator

    我正在尝试创建一个自定义的可迭代对象 这是我的代码的简化示例 class SortedArray Symbol iterator yield 1 yield 2 yield 3 return 4 const testingIterables
  • 在 std::map 中搜索特定值[重复]

    这个问题在这里已经有答案了 可能的重复 检查 std map 中是否存在值 C https stackoverflow com questions 535317 checking value exist in a stdmap c 如何遍历
  • Unity中的LoadScene()函数什么时候改变场景?

    当您调用函数 LoadScene 时 它是立即切换场景 还是只是表示场景需要更改 LoadScene 的文档没有说 我正在使用的具体示例如下所示 LoadScene levelName ItemBox newBox ItemBox Inst
  • 在 Spring 中将 SOAP 1.2 与 WebServiceGatewaySupport 结合使用

    我对 Spring 框架非常陌生 在使用 Spring 创建一个简单的 SOAP 客户端时遇到了一些问题 像一个好的新手一样 我使用 Spring 教程来制作我的 SOAP 客户端 你可以在这里找到它 gt https spring io
  • Unity游戏画面模糊

    我的 Unity 游戏屏幕有问题 当我切换到游戏屏幕时 所有精灵都模糊了 场景视图非常好 但游戏场景很模糊 在 Sprite 的 Unity Inspector 中 您可以将 Generate Mip Map 设置为 false 或者您可以
  • 类叶组件中的 connect() 是 React+Redux 中反模式的标志吗?

    目前正在从事 React Redux 项目 我也在用归一化 https github com gaearon normalizr处理数据结构和reselect https github com reactjs reselect为应用程序组件