React 常见问题

1.React组件划分

按职责划分: UI组件负责UI的呈现,容器组件负责管理数据和逻辑。UI组件嵌套在容器组件中,容器组件通过React-redux提供的connect方法拿到store中的数据。
组件设计原则:
1.高内聚低耦合(组件自身不依赖于其他组件,抽象可复用组件让使用者之间没有耦合关系)
2.周期性迭代(先整体后部分再颗粒化,尽可能抽象)
数据管理原则:
1.能计算得到状态就不要单独存储。
2.组件尽量没有状态,所需数据通过props获取。
具体使用可以参照如下链接:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html

2.React组件的生命周期

Render阶段(暂停),Pre-commit阶段(可读),commit阶段(可用)
1.创建时:
constructor: 组件更新到页面前先创建出来
getDefaultProps: 获取实例的默认属性 (old)
getInitialState: 获取每个实例的初始化状态(old)
componentWillMount: 组件即将被装载、渲染到页面上
render: 组件在这里生成虚拟的DOM节点
componentDidMount: 组件真正在被装载之后可操作了(ajax等)
2.更新时:
getDerivedStateFromProps: 用外部的属性初始化一些内部的状态(16.3引入)
componentWillReceiveProps: 组件将要接收到属性的时候调用 (16.3被取代)
shouldComponentUpdate: 组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了,可用于性能优化)
componentWillUpdate: 组件即将更新不能修改属性和状态
render: 组件重新描绘
getSnapshotBeforeUpdate: 例如获取滚动条滚动高度再减去,不动的效果(16.3引入)
componentDidUpdate: 组件已经更新
3.卸载时:
componentWillUnmount:组件即将销毁

3.React性能优化方案

1.使用production版本
2.使用key来帮助React识别列表中所有子组件的最小变化。
3.重写shouldComponentUpdate来避免不必要的dom操作。(判断是否需要调用render方法重新描绘dom)
参考链接:https://segmentfault.com/a/1190000006254212

4.理解diff算法

把树形结构按照层级分解,只比较同级元素。
给列表结构的每个单元添加唯一的key属性,方便比较。
React只会匹配相同tag class的component(这里面的class指的是组件的名字)
合并操作,调用component的setState方法的时候, React将其标记为dirty.到每一个事件循环结束,React检查所有标记dirty的component重新绘制。
选择性子树渲染。开发人员可以重写shouldComponentUpdate提高diff的性能。
参考链接:https://segmentfault.com/a/1190000000606216

5.虚拟dom如何提高性能

虚拟dom相当于在js和真实dom中间加了一个缓存,利用diff算法避免了没有必要的dom操作,从而提高性能。
步骤:
1.用对象结构表示DOM树的结构,然后用这个树构建一个真正的DOM树,插到文档当中。
2.当状态变更时,重新构造一棵新的对象树。用新的树和旧的树进行比较,记录两棵树差异。
3.把记录的差异应用到最开始构建的真正的DOM树上,视图就更新了。
参考链接:https://www.zhihu.com/question/29504639?sort=created

6.flux工作流程

最大特点:”单向数据流”。
1.用户访问View
2.View发出用户的Action
3.Dispatcher收到Action,要求Store进行相应的更新
4.Store更新后,发出一个”change”事件
5.View 收到”change”事件后,更新页面
参考链接:http://www.ruanyifeng.com/blog/2016/01/flux.html

7.redux中间件

中间件提供第三方插件的模式,自定义拦截 action -> reducer 的过程。
变为 action -> middlewares -> reducer 。
这种机制可以让我们改变数据流,实现如异步 action ,action 过滤,日志输出,异常报告等功能。
常见的中间件:
redux-logger:提供日志输出
redux-thunk:处理异步操作
redux-promise:处理异步操作,actionCreator的返回值是promise

8.redux有什么缺点

1.一个组件所需要的数据,必须由父组件传过来,而不能像flux中直接从store取。
2.当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate进行判断。

9.React项目中的脚手架

Mern:MERN是脚手架的工具,它可以很容易地使用MongoDB, Express, React and NodeJS生成同构JS应用。它最大限度地减少安装时间,并得到您使用的成熟技术来加速开发。
参考链接:http://www.open-open.com/lib/view/open1455953055292.html

11.在React当中Element和Component的区别?

简单地说,一个React Element描述了你想在屏幕上看到什么。换个说法就是,一个React Element是一些UI的对象表示。一个Read component是一个函数或一个类,它可以接受输入并返回一个React Element (通常是通过JSX,它被转化成一个createElement调用)。

12.可以选择性地传递给setstate的第二个参数是什么,它的目的是什么?

一个回调函数,当setstate结束并re-rendered该组件时将被调用。一些没有说出来的东西是 setstate是异步的,这就是为什么它需要一个第二个回调函数。通常最好使用另一个生命周期方法,而不是依赖这个回调函数,但是很高兴知道它存在。

1
2
3
4
this.setstate( 
{ username : 'tylermcginnis33' } ,
()=> console.log ('setstate has flnlshed and the component re-rende red.')
)

这段代码有什么问题?

1
2
3
4
5
this.setstate ( ( prevstate , props )=> { 
return {
Streak : prevstate.Streak + props.count
}
})

没问题。只是这种写法很少被使用,你也可以传递一个函数给setstate ,它接收到先前的状态和道具并返回一个新的状态,它不仅没有什么问题,而且如果您根据以前的状态( state )设置状态,推荐使用这种写法。

13.为什么要使React.children.map(props.children,()=>)而不是props.children.map(()=>)

因为不能保证props.children将是一个数组.
以此代码为例,

1
2
3
<Parent>
<h1>Welcome.</h1>
</Parent>

在父组件内部,如果我们尝试使用props.children.map映射孩子,则会抛出错误,因为props.children是一个对象,而不是一个数组。
如果有多个子元素React只会使props.children成为一个数组。就像下面这样:

1
2
3
4
<Parent>
<h1>Welcome.</h1>
<h2>props.children will now be an array</h2>
</Parent>

这就是为什么你喜欢React.children.map,因为它的实现考虑到props.children可能是一个数组或一个对象。