手挽手带你学React:二档 React生命周期以及组件开发

8次阅读

共计 8039 个字符,预计需要花费 21 分钟才能阅读完成。

手挽手带你学 React 入门二档, 组件开发的开始,合理运用生命周期和组件,能够让你的开发变地流利又 happy, 这篇文章带你学会创建组件,运用组建。学起来吧!
React 组件生命周期
学习 React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大的帮助. 我们先来看一张图
<img src=”http://img.henrongyi.top/reac…; />
组件初始化的时候
1、getDefaultProps()
设置默认的 props,也可以用 dufaultProps 设置组件的默认属性.
2、getInitialState()
在使用 es6 的 class 语法时是没有这个钩子函数的,可以直接在 constructor 中定义 this.state。此时可以访问 this.props
3、componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改 state。
4、render()
react 最重要的步骤,创建虚拟 dom,进行 diff 算法,更新 dom 树都在此进行。此时就不能更改 state 了。
5、componentDidMount()
组件渲染之后调用,只调用一次。
组件更新的时候 6、componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的 props 时调用。
7、shouldComponentUpdate(nextProps, nextState)
react 性能优化非常重要的一环。组件接受新的 state 或者 props 时调用,我们可以设置在此对比前后两个 props 和 state 是否相同,如果相同则返回 false 阻止更新,因为相同的属性状态一定会生成相同的 dom 树,这样就不需要创造新的 dom 树和旧的 dom 树进行 diff 算法对比,节省大量性能,尤其是在 dom 结构复杂的时候
8、componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改 state,render 的时候会用你更改的值,但是这里面不能调用 this.setState(),会让你陷入死循环
9、render()
组件渲染
10、componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取 dom 节点。
组件卸载的时候
11、componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

// 在我们组件第一次加载完的时候会这样执行生命周期
export default class App extends Component {
constructor(){
super()
this.state={

}
}

// getDefaultProps(){
// es6 不支持这个
// console.log(‘1. 执行 getDefaultProps’)
// 具体用法在下面
// }

// getInitialState(){
// es6 里不用它了
// console.log(‘2. 执行 getInitialState’)
// 这个实际上是上面的 state 在 constructor 实现
// }
componentWillMount(){
console.log(‘3. 执行 componentWillMount’)
}
render() {
console.log(‘4. 执行 render’)
return (

)
}
componentDidMount(){
console.log(‘5. 执行 componentWillMount’)

}
}

// 接 getDefaultProps
// 在 ES6 里这么玩

// 还有一种玩法是 ES7 里面的
// static defaultProps = {
// name: ‘demo’
// }; 这里我们不多讲了。。讲多了该晕了 感兴趣的加我微信 shouzi_1994
App.defaultProps = {
name: ‘demo’
};

// 在我们组件更新的时候我们进行如下生命周期
export default class App extends Component {
constructor(){
super()
this.state={
name:’test’
}
}
componentWillReceiveProps(nextProps){
// props 更新的时候调用
console.log(‘1. 执行 componentWillReceiveProps’)
}
shouldComponentUpdate(nextProps, nextState){
console.log(‘2. 执行 shouldComponentUpdate’)
// 这个需要着重强调,我们优化性能用它很重要!如果我们即将更新的东西和原来的数据相同,return 一个 false 就停止组件更新节约性能
if(nextState.name == this.state.name){
return false
}else{
return true
}
}
componentWillMount(nextProps, nextState){
// 在组件渲染前 调用这个
console.log(‘3. 执行 componentWillMount’)
}
change=()=>{
this.setState({name:’QM’})
}
render() {
console.log(‘4. 执行 render’)
return (
<button onClick={this.change}> 测试 </button>
)
}
componentDidUpdate(){
console.log(‘5. 执行 componentDidUpdate’)
}
componentWillUnmount(){
// 这个在卸载的时候会调用 业务逻辑写里面就好了
}
}
生命周期简单介绍就这些了,真正工作中要根据业务需求来调用,大大增加你的开发效率,处理你开发中遇到的难题。
组件创建
其实我们前面的 App 实际上就是一个组件了,我们类比到 vue 里面,它就是脚手架为我们创建的 App.vue 是一个根组件,我们别的组件都渲染到这个组件的内部就好了。
那么 我们如何创建一个子组件呢?
export default class App extends Component {
constructor(){
super()
this.state={

}
}

render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<Children />
)
}

}

// 下面我们再写一个 class 并且继承 Component 这就是一个组件了

class Children extends Component{
constructor(){
super()
this.state={

}
}
render(){
return(
<h1> 我是子组件 </h1>
)
}
}

组件传参
我们学会了如何创建组件,那么组件怎么传参呢?这个是非常重要的东西,毕竟组件之间不能通讯,那就没有创建它的意义了。
父子传参
在 React 中父子传参极其类似 Vue 直接在标签上填写属性,但是在子组件接收的时候会有所不同
我们接着使用上面的代码
export default class App extends Component {
constructor(){
super()
this.state={

}
}

render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<Children params={“ 我从父组件传过来 ”}/>
)
}

}

// 下面我们再写一个 class 并且继承 Component 这就是一个组件了

class Children extends Component{
constructor(){
super()
this.state={

}
}
// 通过这种形式 我们就可以把父组件的东西传递给子组件了,所有的属性存储在 props 里面,上面我们介绍生命周期的时候,也提了一下如何创建默认 props。这里我们写一下

render(){
return(
<div>
<h1> 我是子组件 </h1>
<h2>{this.props.params}</h2>
</div>
)
}
// 如果父组件没有传递 params 我们又想使用默认的 props 那么就要使用下面的写法
}

Children.defaultProps = {
params: ‘ 我是默认的东西 ’
};

// 设置了默认 props 以后 如果我们不传参就会默认展示我们默认规定好的属性了
插槽(类似 Vue solt)为什么要把插槽放在这里讲解呢?实际上 React 的插槽是通过传参的形式下来的,怎么理解呢?我觉得放进代码中是最容易理解的。
export default class App extends Component {
constructor(){
super()
this.state={

}
}

render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<Children params={“ 我从父组件传过来 ”}>
<div> 传递第一个 </div>
<div> 传递第二个 </div>
<div> 传递第三个 </div>
</Children>
)
}

}

// 下面我们再写一个 class 并且继承 Component 这就是一个组件了

class Children extends Component{
constructor(){
super()
this.state={

}
}
// 通过这种形式 我们就可以把父组件的东西传递给子组件了,所有的属性存储在 props 里面,上面我们介绍生命周期的时候,也提了一下如何创建默认 props。这里我们写一下

render(){
console.log(this.props)
// {children:Array(3)
// params:” 我从父组件传过来 ”}

// children 的内容为 [
// {$$typeof: Symbol(react.element), type: “div”, key: null, ref: null, props: {…}, …},
// {$$typeof: Symbol(react.element), type: “div”, key: null, ref: null, props: {…}, …},
// {$$typeof: Symbol(react.element), type: “div”, key: null, ref: null, props: {…}, …}
// ]
// 我们可以看到 他们被顺序放到了 this.props.children 中 并且 这是个数组 内部存储的就是虚拟 dom

return(
<div>
<h1> 我是子组件 </h1>
{/* 这里我用循环的方式把三个 children 取出来直接渲染即可 */}
{this.props.children.map((item,key)=>{
return item
})}
{/* 我们更加直观一点 */}
{this.props.children[1]}
{this.props.children[0]}
{this.props.children[2]}
{/* 看到这里大家应该可以知道插槽的简单用法了吧 */}
</div>
)
}
// 如果父组件没有传递 params 我们又想使用默认的 props 那么就要使用下面的写法
}

Children.defaultProps = {
params: ‘ 我是默认的东西 ’
};

子传父参在 Vue 中我们可以通过定义函数,以实参的形式传递,在父组件捕获的形式来获取想要传递的参数,那么在 React 中这个办法是否也同样适用呢?答案是肯定的,依旧是通过父组件声明函数,传递给子组件,子组件调用并传入参数,在父组件捕获即可。
export default class App extends Component {
constructor(){
super()
this.state={
myPatams:”test”
}
}
getParams(params){
console.log(params,this)
this.setState({
myPatams:params
})
}
render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<div>
{this.state.myPatams}
<Children params={“ 我从父组件传过来 ”} getParams={this.getParams.bind(this)}></Children>
{/* 这里我们把函数传递下去,一定要 bind this 否则在我们在子组件中使用 bind 来调用的时候,this 的指向会跑到子组件中 我们拿到的参数意义就不大了 当然箭头函数也是完全没问题的 */}
</div>
)
}

}

// 下面我们再写一个 class 并且继承 Component 这就是一个组件了

class Children extends Component{
constructor(){
super()
this.state={

}
}
render(){

return(
<div>
<h1> 我是子组件 </h1>
<button onClick={this.props.getParams.bind(this,” 我是子传过来的参数 ”)}> 子传父参 </button>
{/* 我们在这里调用父组件传递过来的方法,并且传入参数 */}
</div>
)
}
}

Children.defaultProps = {
params: ‘ 我是默认的东西 ’
};

非父非子传参(events 方法)这种非关系型组件传参一般使用 redux 来传参,这里我们还有没学习到,我们借助 node 的 EventEmitter 也可以轻松实现
import React,{Component} from ‘react’
// 首先我们创建一个监听器
import EventEmitter from ‘events’; // 事件监控对象
let emitter = new EventEmitter; // 创建一个事件监控者 普通级别的监听
emitter.setMaxListeners(100000); // 设置监控管理器的最大监听数量
export default class App extends Component {
constructor(){
super()
this.state={
myPatams:”test”
}
}
getParams(params){
console.log(params,this)
this.setState({
myPatams:params
})
}
render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<div>
{this.state.myPatams}
<Children params={“ 我从父组件传过来 ”} getParams={this.getParams.bind(this)}></Children>
{/* 这里我们把函数传递下去,一定要 bind this 否则在我们在子组件中使用 bind 来调用的时候,this 的指向会跑到子组件中 我们拿到的参数意义就不大了 当然箭头函数也是完全没问题的 */}
<ChildrenTwo />
</div>
)
}

}

// 下面我们再写一个 class 并且继承 Component 这就是一个组件了

class Children extends Component{
constructor(){
super()
this.state={
emit:””
}
}
componentWillMount(){
emitter.on(‘childrenEmit’,(param)=>{// 我们在这里设置监听
console.log(param)
this.setState({
emit:param
})
})
}
render(){

return(
<div>
<h1>{this.state.emit}</h1>
<button onClick={this.props.getParams.bind(this,” 我是子传过来的参数 ”)}> 子传父参 </button>
{/* 我们在这里调用父组件传递过来的方法,并且传入参数 */}
</div>
)
}
}

class ChildrenTwo extends Component{
constructor(){
super()
this.state={

}
}
gaveParams(param){
emitter.emit(‘childrenEmit’,param) // 从第二个子组件触发并且传递参数
}
render(){

return(
<div>
<h1> 我是子组件 </h1>
<button onClick={this.gaveParams.bind(this,” 我是 ChildrenTwo 传过来的参数 ”)}> 非父非子传参 </button>
</div>
)
}
}

组件抽离
写了这么多,相信大家差不多会写自己的组件并且在组件中传递参数了,这里还有一个问题,大家是不是发现我的所有组件都写在了一个 JS 内部,这样如果是一个大项目,我们的这个 JS 就会变地非常臃肿,这时候我们就要抽离这个组件。实际上非常简单,用到的就是我们 ES6 的 export 导出 即可 如果只有一个组件 那么 还可以像我们书写 App 这个基础组件一样 使用 export default 默认导出
这里我给大家抽离一下
// App.js
import React,{Component} from ‘react’
import {Children} from ‘./components/Children.js’ // 因为我们的 Children 中使用的是 export 来暴露

//import Children from ‘./components/Children.js’ // 如果使用的是 export default 则应该这样写

export default class App extends Component {
constructor(){
super()
this.state={
myPatams:”test”
}
}
getParams(params){
console.log(params,this)
this.setState({
myPatams:params
})
}
render() {
// 要想使用子组件也很简单 用标签的形式拿进来就好了
return (
<div>
{this.state.myPatams}
<Children params={“ 我从父组件传过来 ”} getParams={this.getParams.bind(this)}></Children>
{/* 这里我们把函数传递下去,一定要 bind this 否则在我们在子组件中使用 bind 来调用的时候,this 的指向会跑到子组件中 我们拿到的参数意义就不大了 当然箭头函数也是完全没问题的 */}
</div>
)
}

}
// children.js
import React,{Component} from ‘react’

// 当我们抽离出来以后 必须要再次引入 react 的必要组件

export class Children extends Component{// 我们这里使用的是 export 来暴露 如果只有一个组件 也可以使用 export default 来暴露
constructor(){
super()
this.state={

}
}
render(){

return(
<div>
<h1> 我是子组件 </h1>
<button onClick={this.props.getParams.bind(this,” 我是子传过来的参数 ”)}> 子传父参 </button>
{/* 我们在这里调用父组件传递过来的方法,并且传入参数 */}
</div>
)
}
}

Children.defaultProps = {
params: ‘ 我是默认的东西 ’
};

大功告成了 代码是不是清晰多了??
总结
这一期内容不多 主要是介绍组件的生命周期 使用方法 以及如何传参,这些内容可全都是干货,工作中会经常经常使用到,希望大家能自己写小 demo 来熟悉一下写法,下一期将会带大家学习 React-Router 以及 context 和高阶组件的创建,为我们学习 Redux 打下基础
视频制作中

正文完
 0