上一个评论功能的案例中,可能会有些同学会对一个地方感到疑惑: CommentList中显示的评论列表数据为什么要通过父组件 CommentApp 用 props 传进来?为什么不直接存放在 CommentList 的 state 当中?例如这样做也是可以的:

class CommentList extends Component {
constructor () {
this.state = { comments: [] }
} addComment (comment) {
this.state.comments.push(comment)
this.setState({
comments: this.state.comments
})
} render() {
return (
<div>
{this.state.comments.map((comment, i) =>
<Comment comment={comment} key={i} />
)}
</div>
)
}
}

如果把这个 comments 放到 CommentList 当中,当有别的组件也依赖这个 comments 数据或者有别的组件会影响这个数据,那么就带来问题了。举一个数据依赖的例子:例如,现在我们有另外一个和 CommentList 同级的 CommentList2 ,也是需要显示同样的评论列表数据。

CommentList2 和 CommentList 并列为 CommentApp 的子组件,它也需要依赖 comments 显示评论列表。但是因为 comments 数据在 CommentList 中,它没办法访问到。

遇到这种情况,我们将这种组件之间共享的状态交给组件最近的公共父节点保管,然后通过 props 把状态传递给子组件,这样就可以在组件之间共享数据了。

在我们的例子当中,如果把 comments 交给父组件 CommentApp ,那么 CommentList 和 CommentList2 都可以通过 props 获取到 comments,React.js 把这种行为叫做“状态提升”。

但是这个 CommentList2 是我们临时加上去的,在实际案例当中并没有涉及到这种组件之间依赖 comments 的情况,为什么还需要把 comments 提升到 CommentApp?那是因为有个组件会影响到 comments ,那就是 CommentInputCommentInput 产生的新的评论数据是会插入 comments 当中的,所以我们遇到这种情况也会把状态提升到父组件。

总结一下:当某个状态被多个组件依赖或者影响的时候,就把该状态提升到这些组件的最近公共父组件中去管理,用 props 传递数据或者函数来管理这种依赖或着影响的行为。

我们来看看状态提升更多的例子,假设现在我们的父组件 CommentApp 只是属于更大的组件树 PostApp 的一部分:

而这个更大的组件树的另外的子树的 CommentsCount 组件也需要依赖 comments来显示评论数,那我们就只能把 comments 继续提升到这些依赖组件的最近公共父组件 PostApp 当中。

现在继续让我们的例子极端起来。假设现在 PostApp 只是另外一个更大的父组件 Index 的子树。而 Index 的某个子树的有一个按钮组件可以一键清空所有 comments(也就是说,这个按钮组件可以影响到这个数据),我们只能继续 commenets 提升到 Index 当中。

你会发现这种无限制的提升不是一个好的解决方案。一旦发生了提升,你就需要修改原来保存这个状态的组件的代码,也要把整个数据传递路径经过的组件都修改一遍,好让数据能够一层层地传递下去。这样对代码的组织管理维护带来很大的问题。到这里你可以抽象一下问题:

如何更好的管理这种被多个组件所依赖或影响的状态?

你可以看到 React.js 并没有提供好的解决方案来管理这种组件之间的共享状态。在实际项目当中状态提升并不是一个好的解决方案,所以我们后续会引入 Redux 这样的状态管理工具来帮助我们来管理这种共享状态,但是在讲解到 Redux 之前,我们暂时采取状态提升的方式来进行管理。

对于不会被多个组件依赖和影响的状态(例如某种下拉菜单的展开和收起状态),一般来说只需要保存在组件内部即可,不需要做提升或者特殊的管理。

课后练习


因为第三方评论工具有问题,对本章节有任何疑问的朋友可以移步到 React.js 小书的论坛 发帖,我会回答大家的疑问。

React.js 小书 Lesson17 - 前端应用状态管理 —— 状态提升的更多相关文章

  1. React.js 小书 Lesson2 - 前端组件化(一):从一个简单的例子讲起

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson2 转载请注明出处,保留原文链接和作者信息. 很多课程一上来就给大家如何配置环境.怎么写 Re ...

  2. React.js 小书 Lesson3 - 前端组件化(二):优化 DOM 操作

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson3 转载请注明出处,保留原文链接和作者信息. 看看上一节我们的代码,仔细留意一下 change ...

  3. React.js 小书 Lesson4 - 前端组件化(三):抽象出公共组件类

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson4 转载请注明出处,保留原文链接和作者信息. 为了让代码更灵活,可以写更多的组件,我们把这种模 ...

  4. 【React.js小书】动手实现 React-redux(五):Provider - 方志

    我们要把 context 相关的代码从所有业务组件中清除出去,现在的代码里面还有一个地方是被污染的.那就是 src/index.js 里面的 Index: 1234567891011121314151 ...

  5. React.js 小书介绍

    React.js 小书 Github 关于作者 这是一本关于 React.js 的小书. 因为工作中一直在使用 React.js,也一直以来想总结一下自己关于 React.js 的一些知识.经验.于是 ...

  6. React.js小书总结

    (迁移自旧博客2017 08 27) 第一阶段 react的组件相当于MVC里面的View. react.js 将帮助我们将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合.嵌套,就成 ...

  7. React.js 小书 Lesson16 - 实战分析:评论功能(三)

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson16 转载请注明出处,保留原文链接和作者信息. 接下来的代码比较顺理成章了.修改 Commen ...

  8. React.js 小书 Lesson12 - state vs props

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson12 转载请注明出处,保留原文链接和作者信息. 我们来一个关于 state 和 props 的 ...

  9. React.js 小书 Lesson5 - React.js 基本环境安装

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson5 转载请注明出处,保留原文链接和作者信息. 安装 React.js React.js 单独使 ...

随机推荐

  1. 【转载】C# DataGridView 通过代码设置样式

    // 表格上下左右自适应 dataGridView.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | An ...

  2. EF 配置实现建表与迁移

    通过EF 作为操作数据库的工具有一段时间了,也做了几个相对不大的项目,慢慢的也对EF的使用摸索出来了一些规则,虽然说不是技术难点,但是,我说的是但是,能够提高我们开发效率的棉花糖有时我们还是必须要吃的 ...

  3. 全新的membership框架Asp.net Identity

    在Asp.net上,微软的membershop框架经历了Asp.net membership到Asp.net simple membership,再到现在的Asp.net Identity. 每一次改 ...

  4. Day3作业 .

    ,))::])]): :-])# 3,使用while和for循环分别打印字符串s=’asdfer’中每个元素. # 4,实现一个整数加法计算器:# 如:content = input(‘请输入内容:’ ...

  5. spring (1)

    相关名词: 控制反转(IoC):将对象的创建交由spring创建,1创建新class,2xml中配置 3测试context.getBean("") 类似对象工厂(工厂模式)-xml ...

  6. JS内置对象的原型不能重定义?只能动态添加属性或方法?

    昨天马上就快下班了,坐在我对面的同事突然问我一个问题,我说“爱过”,哈哈,开个玩笑.情况是这样的,他发现JS的内置对象的原型好像不能通过字面量对象的形式进行覆盖, 只能动态的为内置对象的原型添加属性或 ...

  7. .Generator与其他异步处理方案

    1.Generator与其他异步处理方案 以前,异步编程的方法,大概有下面四种. 1.1 回调函数 JavaScript 语言对异步编程的实现,就是回调函数.所谓回调函数,就是把任务的第二段单独写在一 ...

  8. uC/OS-II 一些函数简介

    获得更多资料欢迎进入我的网站或者 csdn或者博客园 以前搞硬件的经验,最近突然翻出来了.分享给大家:主要讲解uC/OS-II常用函数:虽说现在转行软件了,但是感觉之前搞硬件的经验还真是很有用对于理解 ...

  9. 《条目十八》避免使用vector<bool>

    <条目十八>避免使用vector 先说结论: 一是:vector<bool>不是标准容器,因为标准容器的对于T *p = &c[0];必须是可编译的. 二是:vecto ...

  10. C++中define与const的区别

    C++中不但可以用define定义常量还可以用const定义常量,它们的区别如下: 用#define MAX 255定义的常量是没有类型的,所给出的是一个立即数,编译器只是把所定义的常量值与所定义的常 ...