根据胡子大哈的文章学习,感谢大胡分享
胡子大哈-第二阶段
一、理解状态管理
状态管理是为了解决一个问题:
如何高效的管理被多个组件依赖或影响的状态?
state和props都是状态池,里边的字段就是状态。
当父组件中有多个子组件需要某个状态,那么这个时候,这个状态要保存在父组件来达到共享。
但是,如果父组件只是爷爷组件的其中一个孩子,而其他的父组件的兄弟组件也需要这个状态。那么这个状态就要保存在爷爷组件。
如上循环,这种将某个状态往外层放的情况,叫做状态提升。
在实际项目中,可能遇到,嵌套较深的两个组件依赖同一个状态的情况,这个时候如果使用状态提升的方法,就需要把这个状态提升到很外层的组件里,显然不是一个好方法
Redux就是解决这个问题的,关于它,将在下一阶段复习
一般的不被多个组件依赖的状态,内部保存就行。
二、生命周期
1.组件挂载
过程:
实例化组件(constructor())-->调用render生成元素对象(react.js)-->将元素对象构建成dom对象(reactDOM)-->插入页面
以上就是挂载。
抽象一下,就是这个过程
-> constructor()
-> render()
-> 构造dom
-> 插入页面
2.挂载生命周期与控制钩子
- 为了更好的控制挂载过程
React.js提供了两个钩子
componentWillMount()
、componentDidMount()
两个方法在组件内部定义,
在组件的render
之前调用componentWillMount()
。
在DOM元素插入页面后调用componentDidMount()
。
抽象下
-> constructor()
-> componentWillMount()
-> render()
-> 构造dom
-> 插入页面
-> componentDidMount()
- 完善过程——删除页面钩子
完善上边抽象的过程
-> constructor()
-> componentWillMount()
-> render()
-> 构造dom
-> 插入页面
-> componentDidMount()
...
-> 将从页面中删除
-> 已从页面中删除
React.js同样控制了这个过程,componentWillUnmount()
-> constructor()
-> componentWillMount()
-> render()
-> 构造dom
-> 插入页面
-> componentDidMount()
...
-> 将从页面中删除
-> componentWillUnmount()
-> 已从页面中删除
注:
删除一个组件是很经常的,一个标签的隐藏和显示{this.state.isShow ? <App /> : null}
类似这样的逻辑。
-
挂载过程的一些说明
constructor
:初始化工作,比如state
componentWillMount
:一些组件启动时的行为,比如Ajax、定时器
componentWillUnmount
:清场工作,比如取消定时器,防止各种错误,比如内存泄漏。
3.更新阶段组件生命周期
更新过程:
setState --> render --> dom --> 插入页面
要理解这个过程,就需要对virtual--DOM有比较深刻的认识,这些将在第四阶段复习。
接下来,大概了解下更新过程和这个过程中的钩子钩子函数
shouldComponentUpdata(nextProps, nextState)
:通过这个方法,控制组件是否重新渲染。
componentWillReceiveProps(nextProps)
:组件从父组件接收新的props
之前调用
componentWillUpdate()
:组件开始重新渲染之前调用
componentDidUpdate()
:组件重新渲染并且把更改变更到真实的DOM以后调用
4.小总结
这里引用一些网上文章的内容
下文引用自NsNe的博客
每个组件都有几个生命周期函数,以will为前缀的函数是在发生某些事之前调用,以did为前缀的是在发生某些事之后调用
1.Mounting
如下这些方法在组件实例被创建和被插入到dom中时被调用。
constructor()
componentWillMount()
此方法在mounting之前被立即调用,它在render()之前调用,因此在此方法中setState不会触发重新渲染。此方法是服务器渲染中调用的唯一的生命周期钩子,通常我们建议使用constructor()。render()
componentDidMount()
此方法在组件被mounted之后立即被调用,初始化dom节点应该在此方法中,如果需要从远端健在数据,这里是实例化网络请求的好地方,此方法中setState会触发组件重新渲染。
Updating
props和state的改变产生更新。在重新渲染组建时,如下的方法被调用
-
componentWillReceiveProps()
一个已经mounted的组件接收一个新的props之前componentWillReceiveProps()被调用,如果我们需要更新state来响应prop的更改,我们可以在此方法中比较this.props和nextProps并使用this.setState来更改state。
注意,即使props没有改变,React也可以调用这个方法,因此如果你只想处理改变,请确保比较当前值和下一个值。当父组件导致你的组件重新渲染时,可能会发生这种情况。
React在组件mounting期间不会调用此方法,只有在一些组件的props可能被更新的时候才会调用。调用this.setState通常不会触发componentWillReceiveProps。 -
shouldComponentUpdate()
使用此方法让React知道组件的输出是否不受当前state或props更改的影响。默认行为是在每次state更改时重新渲染组件,在大多数情况下,我们应该默认改行为。
当接收到新的props或state时,shouldComponentUpdate()在渲染之前被调用。默认返回true,对于初始渲染或使用forceUpdate()时,不调用此方法。返回false不会阻止子组件的state更改时,该子组件重新渲染。
如果shouldComponentUpdate()返回false,那么componentWillUpdate(),render()和componentDidUpdate()将不会被调用。在将来,React可能将shouldComponentUpdate()作为提示而不是strict指令,返回仍然可能导致组件重新渲染。 -
componentWillUpdate()
当接收新的props或state时,componentWillUpdate()在组件渲染之前被立即调用。使用此函数作为在更新发生之前执行准备的机会。初始渲染不会调用此方法。注意:这里不能调用this.setState()(如果调用会怎么样?好奇心很重呀,试了一下,会产生死循环,一直更新。。。)。如果我们需要更新state以响应props的更改,我们应该使用componentWillReceiveProps() render()
-
componentDidUpdate()
此函数在更新后立即被调用。初始渲染不调用此方法。
当组件已经更新时,使用此操作作为DOM操作的机会。这也是一个好的地方做网络请求,只要你比较当前的props和以前的props(例如:如果props没有改变,可能不需要网络请求)。
Unmounting
当从dom中移除组件时,这个方法会被调用
-
componentWillUnmount()
此函数在组件被卸载和销毁之前被立即调用。在此方法中执行一些必要的清理。例如清除计时器,取消网络请求或者清理在componentDidMount中创建的任何DOM元素。
三、ref
流行的前端大框架,基本上都避免了绝大部分的DOM更新操作,jQ基本88。
但是,框架提供的功能并不能满足所有的需求。所以,有时候还是要和DOM打交道。
比如动态获取某个元素尺寸,然后做动画。
React.js的ref属性
通过这个属性,可以获取已经挂载的元素对应的真实DOM节点。
用法:
<Index ref={(Index) => this.index = Index} />
当然,一般是标签,不是组件,这里只是示例。
布局
一般情况下,在写页面的时候,会有很多容器标签,来给页面布局。组件化开发,同理,就会有一些容器组件,用来布局。
如何方便的使用这些组件?既然是容器组件,那么调用组件的时候,是不是要传入容器里的内容,然后让容器渲染呢?
通过porps,在字段中书写JSX显然是不方便的。React.js提供了props.children
属性,它是一个数组,保存了调用组件时,组件闭合标签内的结构。
在组件内部,就可以直接使用这个属性了。
class Layout extends Component {
render () {
return (
<div className='two-cols-layout'>
<div className='sidebar'>
{this.props.children[0]}
</div>
<div className='main'>
{this.props.children[1]}
</div>
</div>
)
}
}
...// 调用的时候
某个组件调用Layout组件
render () {
return (
<Layout>
<div>你们好</div>
<div>哈哈哈</div>
</Layout>
)
}
五、dangerouslySetInnerHTML
为避免xss,React.js将所有通过表达式插入的内容自动转义——>字符串
如何向其中插入HTML结构(innerHTML)?
<div
className='editor-wrapper'
dangerouslySetInnerHTML={{__html: this.state.content}} />
// this.state.content: <div>一个标签</div>
六、style
在标签中,style字段接收一个对象,而不是原生的字符串。
在对象中,对应css字段命,使用小驼峰命名。eg:background-color——>backgroundColor
因为style是一个对象,我们就可以使用状态池中的状态了,很方便。
七、数据验证
1.理解验证的重要性
多人协作,组件复用,没有验证,健壮性就太差。
2.React.js的验证机制
- 引入
prop-types
包 - 定义
propTypes
字段,对输入进行检查 -
propTypes
提供的参数
PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.node
PropTypes.element
等等
多人协作开发,写类型检查吧,省事好维护
(完)