vanilla

  1. import "./styles.css";
  2. // create div
  3. let div = document.createElement("div");
  4. div.style.border = "1px solid red";
  5. let state = 0;
  6. div.innerHTML = `
  7. <p>${state}</p>
  8. <button>+1</button>
  9. <button>die</button>
  10. `;
  11. let app = document.getElementById("app");
  12. // mount
  13. app.appendChild(div);
  14. div.querySelector("button").onclick = () => {
  15. state += 1;
  16. // update => render
  17. div.querySelector("p").innerText = state;
  18. };
  19. div.querySelectorAll("button")[1].onclick = () => {
  20. div.querySelector("button").onclick = null;
  21. div.querySelectorAll("button")[1].onclick = null;
  22. div.remove(); // unmount
  23. div = null;
  24. };

React

class组件生命周期

constructor

用途:

  • 初始化state
  • 初始化props
  • bind this
    shouldComponentUpdate
    作用:允许我们手动判断是否要进行组件更新,我们可以根据应用场景灵活地设置返回值,以避免不必要的更新。返回true表示不阻止UI更新,返回false表示阻止UI更新
    1. shouldComponentUpdate(newProps, newState){
    2. if(newState.n === this.state.n){
    3. return false
    4. } else {
    5. return true
    6. }
    7. }
    可以使用React.PureComponent代替React.Component
    PureComponent 会在 render 之前对比新 state 和旧 state 的每一个 key,以及新 props 和旧 props 的每一个 key。如果所有 key 的值全都一样,就不会 render;如果有任何一个 key 的值不同,就会 render。

render

用途:
展示视图

  1. render(){
  2. if (this.state.n % 2 === 0) {
  3. return <div>偶数</div>
  4. } else {
  5. return <div>奇数</div>
  6. }
  7. }

只能返回一个根元素,如果有2个根元素,可以用标签(<></>)包起来
render用array.map写for循环

  1. render(){
  2. return this.state.array.map(n=><div>{n}</div>)
  3. }

componentDidMount

在元素插入页面后执行代码,这些代码依赖DOM

  1. componentDidMount() {
  2. const div = document.getElementById('xxx')
  3. const {width} = div.getBoundingClientRect()
  4. this.setState({width})
  5. }

此处可以发起加载数据的AJAX请求(官方推荐)
首次渲染会执行此钩子

使用ref 防止ID冲突

  1. calss App extends React.Component {
  2. divRef = undefined
  3. constructor(props) {
  4. super(props)
  5. this.state = {
  6. n: 1,
  7. width: undefined
  8. }
  9. this.divRef = React.createRef()
  10. }
  11. render(){
  12. return (
  13. <div ref={this.divRef}>Hello World, {this.state.width}</div>
  14. )
  15. }
  16. componentDidMount(){
  17. const div = this.divRef.current
  18. const {width} = div.getBoundingClientRect()
  19. this.setState({width})
  20. }
  21. }

componentDidUpdate

在视图更新后执行代码
也可以发起AJAX请求,用于更新数据
首次渲染不会执行此钩子
若shouldComponentUpdate返回false,则不触发此钩子

componentWillUnmount

组件将要被移除页面然后销毁时执行代码
unmount过的组件不会再次mount

在unmount里取消监听,取消Timer, 取消AJAX请求,谁污染谁治理

其他钩子

getDerivedStateFromProps
getSnapshotBeforeUpdate
getDerivedStateFromError
componentDidCatch

被废除的钩子

componentWillMount
componentWillReceiveProps
componentWillUpdate

分阶段看钩子执行顺序
  • 首次渲染:constructor -> render -> componentDidMount
  • 再次渲染:shouldComponentUpdate -> render -> componentDidUpdate
  • 销毁: componentWillUnmount

    函数组件模拟生命周期

    componentDidMount
    1. useEffect(()=>{console.log('第一次渲染')}, [])
    componentDidUpdate
    1. useEffect(()=>{console.log('任意属性变更')})
    2. useEffect(()=>{console.log('n变了')}, [n])
    componentWillUnmount
    1. useEffect(()=>{
    2. console.log('第一次渲染')
    3. return ()=>{
    4. console.log('组件要死了')
    5. }
    6. })