# 类组件和函数组件

React 组件分为:类组件和函数组件。

类组件:

class Demo extends React.Component {
  render() {
    return <span>demo</span>
  }
}

函数组件:

function Demo() {
  return <span>demo</span>
}

在 React 调和和渲染 fiber 节点的时候,如果 fiber tag 是 ClassComponent = 1,就按照类组件的逻辑处理,如果是 FunctionComponent = 0 则按照函数组件处理。

类组件的底层定义:

// react/src/ReactBaseClasses.js

function Component(props, context, updater) {
  // 子组件必须调用 super(props),要不就找不到 props 了
  this.props = props;      //绑定props
  this.context = context;  //绑定context
  this.refs = emptyObject; //绑定ref
  this.updater = updater || ReactNoopUpdateQueue; //上面所属的updater 对象
}
/* 绑定setState 方法 */
Component.prototype.setState = function(partialState, callback) {
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
}
/* 绑定forceupdate 方法 */
Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
}

对于类组件的执行:

// react-reconciler/src/ReactFiberClassComponent.js

function constructClassInstance(
  workInProgress, // 当前正在工作的 fiber 对象
  ctor,           // 我们的类组件
  props           // props 
){
  /* 实例化组件,得到组件实例 instance */
  const instance = new ctor(props, context)
}

对于函数组件的执行:

// react-reconciler/src/ReactFiberHooks.js

function renderWithHooks(
  current,          // 当前函数组件对应的 `fiber`, 初始化
  workInProgress,   // 当前正在工作的 fiber 对象
  Component,        // 我们函数组件
  props,            // 函数组件第一个参数 props
  secondArg,        // 函数组件其他参数
  nextRenderExpirationTime, //下次渲染过期时间
){
  /* 执行我们的函数组件,得到 return 返回的 React.element对象 */
  let children = Component(props, secondArg);
}

类组件各个部分的功能:

class Index extends React.Component{
    constructor(...arg){
       super(...arg)                        /* 执行 react 底层 Component 函数 */
    }
    state = {}                              /* state */
    static number = 1                       /* 内置静态属性 */
    // 触发click的话会优先触发这个方法,因为它是绑定在实例上的
    handleClick= () => console.log(111)     /* 方法: 箭头函数方法直接绑定在this实例上 */
    componentDidMount(){                    /* 生命周期 */
        console.log(Index.number,Index.number1) // 打印 1 , 2 
    }
    render(){                               /* 渲染函数 */
        return <div style={{ marginTop:'50px' }} onClick={ this.handerClick }  >hello,React!</div>
    }
}
Index.number1 = 2                           /* 外置静态属性 */
Index.prototype.handleClick = ()=> console.log(222) /* 方法: 绑定在 Index 原型链的 方法*/

上面的 handleClick= () => console.log(111) 如果我们写成普通函数会怎样呢?

 

函数组件每次更新的时候都需要重新执行一次;类组件,底层只需要实例化一次,每次更新只需要调用 render 函数和相应的生命周期方法即可。

# 组件通信方式

主流通信方式:

  • props 和 callback

父组件通过 props 将数据传递给子组件;子组件通过调用父组件中的方法来实现与父组件通信;

function Parent() {
  const [ content, setContent ] = useState('I love you');
  return <Child content={content} setContent={(val) => setContent(val)}/>
}

function Child({ content, setContent }) {
  return <span onClick={() => setContent('I love you, too')}>{content}</span>
}
  • ref
  • React Redux等状态管理
  • context
  • event bus 事件总线

如果你学过 Vue 的话,看到这个是不是很熟悉。这种通信方式在 Reac 中是不推荐的:

  • 需要手动绑定和解绑;
  • 维护起来比较困难;