React(三)-类组件以及hooks

792 阅读5分钟

一、类组件的写法

class B extends React.Component {
    constructor(props) {
    super(props);
}
render(){
        return (
            <div>hi</div> 
        )
    }
}
export default B;

constructor 的参数是 new B(props) 用到的,super 的参数是父类构造函数用的,我们使用时用constructor接受props,然后用super把props传递个父类,父类挂靠到实例上(代替了我们自己挂靠上去)。

我们直接标签使用<B/>即可

二、props

初始化:super

读:this.props.xxx 即可读取

写:不要改写props,通知父元素去修改props

接受外部函数或数据

三、state

初始化:constructor里写this.state = {}

读:this.state.xxx

写:setState(()=>{})

四、生命周期钩子

  1. let div = document.createElement('div )       //这是div的create / construct过程 
  2. div.textContent= 'hi'       //这是初始化state 
  3. document.body.appendChild(div)     //这是div的mount过程 
  4. div.textContent= 'hi2'  //这是div的update过程 
  5. div.remove()       //这是div的unmount过程 

一、constructor

就是类的构造函数

初始化props 初始化state,但此时不能调用setState,用来写bind this 

 constructor( ){ 
    this.onClick = this.onClick.bind(this) 
}

 可以用新语法代替

 onClick = ( )=>{} 

二、shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState)

根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。

当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

可以将 this.propsnextProps 以及 this.statenextState 进行比较,并返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。

shouldComponentUpate的用意:

因为种种原因,通过计算得出来的新state和旧state一样,那么就会执行render,两次虚拟dom比较,对比后发现没有变化,不更新UI。shouldCompontentUpdate目的就是为了跳过render函数调用。

其实React同样内置了这个函数:

React.PureComponentReact.Component 很相似。两者的区别在于 React.Component 并未实现 shouldComponentUpdate(),而 React.PureComponent 中以浅层对比 prop 和 state 的方式来实现了该函数。

三、render

render 被调用时,它会检查 this.propsthis.state 的变化并返回以下类型之一:

  • React 元素。通常通过 JSX 创建。例如,<div /> 会被 React 渲染为 DOM 节点,<MyComponent /> 会被 React 渲染为自定义组件,无论是 <div /> 还是 <MyComponent /> 均为 React 元素。只有一个根元素
  • 数组或 fragments。 使得 render 方法可以返回多个元素。<React.Fragment></React.Fragment>render后会消失,只是占位用。可以用<></>代替

render() {return this.state.array.map(n= <span>key={n}>{n}</span> )

  • Portals。可以渲染子节点到不同的 DOM 子树中。
  • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
  • 布尔类型或 null。什么都不渲染。(主要用于支持返回 test && <Child /> 的模式,其中 test 为布尔类型。)

message = <div>xxx</div>
<>
    {message}
</>

render所有的循环都要有key

四、componentDidMount

componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。类似于Vue的mounted。获取一个div的宽度等等

你可以在 componentDidMount() 里直接调用 setState()。用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理

五、compontentDidUpate

componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。

你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。

在此处进行网络请求,一般是有关更新数据的

六、compontentWillUnmount

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

componentWillUnmount()不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

remove和实例赋值为null都进行

这个钩子调用后该组件将永远不会重新渲染,若要重新渲染只能重新创建。

如果你在C.. DidMount里面监听了window scroll 那么你就要在c..WillUnmount里面取消监听 

window.scroll = function(){} =>   window.scroll = null

如果你在c..DidMount里面创建了Timer 那么你就要在c.WillUnmount里面取消Timer 在观看 如果你在c..DidMount里面创建了AJAX 请求 那么你就要在c.WillUnmount里面取消请求,AJAX请求没结束实例就死了

七、执行顺序

  • constructor()-初始化
  • shouldComponentUpdate()-渲染前首次渲染不会触发
  • render()-渲染
  • componentDidUpdate()-渲染后首次渲染不会触发
  • componentDidMount()-挂载后立即
  • compontentWillUnmount-销毁前

=====

首次渲染

  • constructor()-初始化
  • render()-渲染虚拟DOM
  • UI更新-挂载DIFF
  • componentDidMount()-挂载后立即

八、一些小东西

render阶段产生一个虚拟DOM,

appendChild阶段(mount)对比两个虚拟DOM更新视图

九、异步的setState

  increment = () => {
    this.setState({ val: this.state.val + 1 })
    console.log(this.state.val) // 输出的是更新前的val --> 0
  }

不要指望在调用 setState 之后,this.state 会立即映射为新的值。要想得到新的值下面代码即可。

  increment = () => {
    this.setState(state=>{
       val = state.val + 1
       console.log(val)
       return {val}
     })
  }

对新值执行一些函数