学习react第六天-再次认识组件

85 阅读3分钟

经过一天周末的休息,和周一忙碌的面试,继续开始react的学习,经过前面的学习(主要是官网),我大概了解react的一些理念和基础的皮毛。为了加深印象,继续学习react组件,看看大佬们怎么做。这里react的版本有了变化 不再是V18了。

组件可以分为两类,一类是类( Class )组件,一类是函数( Function )组件。

类( Class )组件,函数( Function )组件的本质和区别是什么?

/* 类 */
class myClass {
    sayHello=()=>console.log('hello, my class')
}
/* 类组件 */
class MyClass extends React.Component{
    state={ message:`hello ,Class!` }
    sayHello=()=> this.setState({ message : 'hello, my class' })
    render(){
        return <div style={{ marginTop:'50px' }} onClick={ this.sayHello } > { this.state.message }  </div>
    }
}
/* 函数 */
function textFun (){ 
    return 'hello, class'
}
/* 函数组件 */
function FunComponent(){
    const [ message , setMessage ] = useState('hello,class')
    return <div onClick={ ()=> setMessage('hello, my class')  } >{ message }</div>
}

这里我觉得只是写法不同,两种组件承载了渲染视图的 UI 和更新视图的 setState 、 useState 等方法,但是我们需要了解在 React 调和渲染 fiber 节点的时候,如果发现 fiber tag 是 ClassComponent = 1,则按照类组件逻辑处理,如果是 FunctionComponent = 0 则按照函数组件逻辑处理。

class类组件

那么到底什么是类组件呢?

类组件的定义

在 class 组件中,除了继承 React.Component ,底层还加入了 updater 对象,组件中调用的 setState 和 forceUpdate 本质上是调用了 updater 对象上的 enqueueSetState 和 enqueueForceUpdate 方法。

React 处理组件的逻辑

Component 底层 React 的处理逻辑是,类组件执行构造函数过程中会在实例上绑定 props 和 context ,初始化置空 refs 属性,原型链上绑定setState、forceUpdate 方法。对于 updater,React 在实例化类组件之后会单独绑定 update 对象。

类组件的构成

class Index extends React.Component{
    constructor(...arg){
       super(...arg)                        /* 执行 react 底层 Component 函数 */
    }
    state = {}                              /* state */
    static number = 1                       /* 内置静态属性 */
    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 原型链的 方法*/

函数组件

ReactV16.8 hooks 问世以来,对函数组件的功能加以强化,可以在 function 组件中,做类组件一切能做的事情,甚至完全取缔类组件。

import { useState } from 'react';
export default function Gallery() {
      const [index, setIndex] = useState(0); /* hooks */

      function handleClick() {
        setIndex(index + 1);
     }
     return (
        <>
        // onClick={handleClick}
        <>
      )
 }

对于类组件来说,底层只需要实例化一次,实例中保存了组件的 state 等状态。对于每一次更新只需要调用 render 方法以及对应的生命周期就可以了。但是在函数组件中,每一次更新都是一次新的函数执行,一次函数组件的更新,里面的变量会重新声明。

组件的通讯方式

React 一共有 5 种主流的通信方式:

  1. props 和 callback 方式(vue props和回调)

  2. ref 方式。(vue3 ref调用属性和事件)

  3. React-redux 或 React-mobx 状态管理方式。(Pinia,vueX)

  4. context 上下文方式。Vue3 中 Context的用法

    // Attribute (非响应式对象)
    console.log(context.attrs)
    
    // 插槽 (非响应式对象)
    console.log(context.slots)
    
    // 触发事件 (方法)
    console.log(context.emit)
    
  5. event bus 事件总线。(vue bus总线,需要手动挂载取消,复杂业务状态有位置影响,都违背了数据单象传递)

props 和 callback

上文提过,属性传递,可以传 整个props也可以把属性分开传递,这里的传递类似于vue的props:

父组件 -> 通过自身 state 改变,重新渲染,传递 props -> 通知子组件

子组件 -> 通过调用父组件 props 方法 -> 通知父组件。

实现父子组件之间的通信,这里拿。

/* 子组件 */
function Son(props){
    const {  fatherSay , sayFather  } = props
    return <div className='son' >
         子组件
        <div> 父组改变props:{ fatherSay } </div>
        <input placeholder="回调父组件说" onChange={ (e)=>sayFather(e.target.value) }   />
    </div>
}
/* 父组件 */
function Father(){
    const [ childSay , setChildSay ] = useState('')
    const [ fatherSay , setFatherSay ] = useState('')
    return <div className="box father" >
        父组件
       <div> 子组件回调展示:{ childSay } </div>
       <input placeholder="修改props传递的内容" onChange={ (e)=>setFatherSay(e.target.value) }   />
       <Son fatherSay={fatherSay}  sayFather={ setChildSay }  />
    </div>
}

最后关于类组件的继承,这里我的设想是 使用ts感觉更好一些,后续来实践。