上一个评论功能的案例中,可能会有些同学会对一个地方感到疑惑: 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. 移植 libevent-2.0.22-stable 到ARM平台

    ARM 移植: 移植简单来讲就是使用ARM的编译环境,重新编译一份ARM平台上可以使用的库或执行文件,一般只需要重新制定C编译器和C++编译器即可. 特别注意的地方: 不能从windows解压文件后再 ...

  2. WinForm中的重绘 - 文本的重绘

    两种方式 TextRenderer.DrawText 注意:默认在每次绘制的文本左右有padding,即使参数中设置了TextFormatFlags.NoPadding也是一样,因此在分段绘制文本时( ...

  3. C# 接口(3)

    这么半天说了如何使用,实现接口.相信也都发现了接口和抽象类很多相似的地方. 但是! 这两个根本就是不一样的. 抽象类 :                                         ...

  4. Kotlin 在kotlin内使用Java的一些注意(长篇)

    首先呢,大部分的java在kotlin内是可以使用的. 但是有些java的关键字和kotlin的一样,而意义不一样就需要转义.(单引号括起来的)这一点需要注意. 这是一个长篇 我会不断更新.毕竟我也在 ...

  5. win7系统电脑显示windows副本不是正版怎么办

    win7系统电脑显示windows副本,可以:在开始输入框中输入cmd——以管理员权限运行——在命令行中输入SLMGR -REARM,——重启.

  6. MongDB集群部署

    http://blog.csdn.net/luonanqin/article/details/8497860 参数解释: dbpath:数据存放目录 logpath:日志存放路径 pidfilepat ...

  7. 老男孩Day17作业:后台管理平台编辑表格

    一.作业需求: 后台管理平台 ,编辑表格: 1. 非编辑模式: 可对每行进行选择: 反选: 取消选择 2. 编辑模式: 进入编辑模式时如果行被选中,则被选中的行万变为可编辑状态,未选中的不改变 退出编 ...

  8. CentOS修改默认yum源为国内yum镜像源

    修改CentOS默认yum源为mirrors.163.com 1.首先备份系统自带yum源配置文件/etc/yum.repos.d/CentOS-Base.repomv /etc/yum.repos. ...

  9. ubuntu16.04 chromium浏览器无法启动

    点击浏览器不能启动,在终端输入: chromium -browser %U 错误如下: [/)] NSS_VersionCheck("3.26") failed. NSS > ...

  10. tornado 10 长轮询和 websocket

    tornado 10 长轮询和 websocket 一.长轮询 #在网页,我们经常扫码登录,那么问题来了,前端是如何知道用户在手机上扫码登录的呢 这里就需要用到长轮询 #长轮询 #客户端能够不断地向服 ...