1. 场景描述

在做个人项目的时候, 发现了一个问题: ant design UI 框架中, Select 组件的 defaultValue 属性失效了, 即设置了defaultValue 值缺没有默认的选定内容;

上面这个问题可以抽象成为如下沙盒:
PS: 该沙盒最好在codesandbox 网站下运行

import React from "react";
import { Select } from 'antd';
const { Option } = Select;

import 'antd/dist/antd.css'

const log = console.log.bind(console)

class App extends React.Component{
    constructor(props) {
        super(props)
        this.state = {
          
        }
    }

    // 1. 当生命周期函数为componentDidMount 时, 执行的顺序应该为:
    // constructor -> render -> componentDidMount -> render;
    // 而控制台显示执行了4次render, 这是为什么? 
    
    // 2. 当生命周期函数为componentDidMount 时, 在最后一次执行render时, 
    // defaultValue 属性已经被赋值为here, 为什么这个属性没有效果
    // componentDidMount() {
    // this.setState({
    // defaultValue: 'here'
    // })
    // }

    // 3. 当生命周期函数为componentWillMount 时, 执行的顺序为:
    // constructor -> componentWillMount -> render(加载过程默认的)-> render(this.setData 更新过程触发的);
    // 那么为什么两次控制台输出都是here, 这是由于consolo.log 的限制造成的吗?
    // componentWillMount() {
    // this.setState({
    // defaultValue: 'here'
    // })
    // }

    
    render() {
      let {defaultValue} = this.state
      log('执行了render 函数 defaultValue = ', String(defaultValue))
      return (
          <>
            <Select value={defaultValue} style={{ width: 120 }}>
              <Option value="jack">Jack</Option>
              <Option value="lucy">Lucy</Option>
              <Option value="here">
                here
              </Option>
              <Option value="Yiminghe">yiminghe</Option>
            </Select>
          </>
      )
    }
}

export default App

2. 问题描述即解答

2.1 组件渲染两次?

当生命周期函数为componentDidMount 时, 执行的顺序应该为: constructor -> render -> componentDidMount -> render; 而控制台显示执行了4次render, 这是为什么?

运行结果:

上面的沙盒(demo)运行环境为: codesandbox, 如果是在本地自建React 项目, 将不会运行4次, 而应该是2次

因为 React 在 Dev mode 下会刻意执行两次渲染,以防止组件内有什么 side effect 引起 bug,提前预防; 详细内容可以参见如下地址: 为什么 react 的函数组件每次渲染执行两次?

2.2 ant design Select defaultValue 属性失效

当生命周期函数为componentDidMount 时, 在最后一次执行render时, defaultValue 属性已经被赋值为here, 为什么这个属性没有效果

因为组件第一次加载的时候会取defaultValue,之后重新渲染将不会处理defaultValue。如果重新渲染组件时, 还需要加载默认值, 则使用value 属性; 详细内容可以参见如下地址: ant design Select API

其实这个严格上来说是自己没有好好看文档, 先入为主了.

2.3 componentWillMount 生命周期

当生命周期函数为componentWillMount 时, 执行的顺序为: constructor -> componentWillMount -> render(加载过程默认的)-> render(this.setData 更新过程触发的);那么为什么两次控制台输出都是here, 这是由于consolo.log 的限制造成的吗?

首先输出两次的原因是因为组件渲染了两次, 这个可以参考第一个问题;

当生命周期函数为componentWillMount 时, 如果在componentWillMount 生命周期中使用this.setData, 此时this.setData 是一个同步函数, 而非异步函数, 因此render 中defaultValue 的值为 here

值得说明的是 componentWillMount 该生命周期函数已不被官方所推荐, 因此尽量不要使用. 具体内容可以参考如下地址: React 官方文档

this.props 数据应该只在子组件负责渲染; this.props 数据更改应该发生在父组件, 这样更符合生命周期设计(componentWillReceiveProps生命周期方法已不被官方推荐

3. 参考链接

  1. 为什么 react 的函数组件每次渲染执行两次?
  2. ant design Select API
  3. React 官方文档