React源码解析:react-props

434 阅读3分钟

什么是Props?在react中,类组件或者函数组件,父组件绑定在子组件标签里的属性或者方法最终会变成props传递给子组件。

import React from 'react';

class OnePropsComponents extends component{
    render(){
        return(
            <div> hello i am onePropsComponents </div>
        )
    }
}


class TwoPropsComponents extends component{
    render(){
        const { children, mes, renderName, say, Component } = this.props
        const renderFunction = children[0];
        const renderComponent = children[1];
        return(
        <div>
            {mes}
            {renderFunction()}
            {renderComponent()}
            {renderName()}
            <Component/>
            <button onClick={()=>say()}> button </button>
        </div>
        )
    }
}


class Index extends component{
constructor(props) {
    super(props);
    this.state = {
      mes: ' I'm your boyfriend ',
    };
    // 方法注册
    [
      'say',
    ].forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }
    
    say(){
       this.setState({ mes: 'no! you daydreaming'})
    }
    
    render(){
    const {mes}= this.state;
        return(
            <div> 
                <TwoPropsComponents
                    mes={mes} // props 作为渲染数据源
                    say={ this.say } // props 作为回调函数callback
                    Component={ OnePropsComponents } // props 作为一个组件
                    renderName={()=><div> i am shuaige </div>} // props 作为一个渲染函数
                >
                    {()=><div>Content</div>} // render props 放在children属性上
                    <OnePropsComponents /> // 插槽组件
                </TwoPropsComponents>
            </div>
        )
    }
}

image.png

在标签内部的属性和方法会直接绑定在 props 对象的属性上,对于组件的插槽会被绑定在 props 的 Children 属性中。

React 对props的定义:

1、在组件层级:

父组件props可以把数据层传递给子组件渲染消费。

子组件可以通过props中的回调函数(callback)向父组件传递信息。还有一种可以将视图容器作为 props 进行渲染。

2、在react更新机制中:

在fiber调和阶段,diff是React更新的驱动器,在react中 props 可以作为组件是否更新的重要准则,props变化,组件即更新,

3、从插槽层面:

React 可以把组件的闭合标签里的插槽,转化成 Children 属性。

如何监听pros的改变:

在类组件中,使用生命周期函数componentWillReceiveProps/getDerivedStateFromProps监听props的变化,

在函数组件中,可以使用useEffect监听。

props重点 children模式:

1、插槽组件:

<FatherComponent>
    <SonComponent /> // element 对象
</FatherComponent>

在FatherComponent组件中 可以通过 props.children属性 访问到SonComponent组件。

插槽组件的作用:

  1. 可以根据需要控制子组件(SonComponent)是否渲染。
  2. 父组件FatherComponent可以通过React.cloneElement强化 props,或者修改SonComponent的子元素。

2、render props模式:

<FatherComponent>
    {(fatherProps)=><SonComponent {...fatherProps}/>}
</FatherComponent>

FatherComponent中props.children 访问到的是函数,不是element对象,在这种情况下children不能被直接渲染。

错误:

function FatherComponent(props) { 
return props.children 
}

正确:

function FatherComponent(props) { 
const fatherProps={
name: 'zxy',
age: '18',
};
return props.children(fatherProps)
}

作用:

  1. 可以根据需要控制子组件(SonComponent)是否渲染。
  2. 可以将需要传给子组件(SonComponent) 的 props 直接通过函数参数的方式传递给执行函数 children 。

3、混合模式:

<FatherComponent>
    <Component />
    {(sonProps)=><Component {...sonProps} name={'zxy'} />}
</FatherComponent>

import React, {isValidElement} from 'react';

function ChildrenComponent(props){
    return(
        <div>我的名字叫`${props.name}`</div>
        <div>{props.mes}</div>
    )
}

function FatherComponent(props){
    const fatherProps ={
        name: 'zxy',
        mes: 'i am react',
    };

    return props.children.map(item=>{
        if(isValidElement(item)){ // isValidElement 判断是否是react 组件(element) 
            return cloneElement(item, {...fatherProps}, item.props.children) //针对节点(element)通过cloneElement 混入 props
            
        }else if(typeof item==='function'){
            return item(fatherProps) //针对函数 直接传递参数,执行函数。
        }else{
            return null;
        }
    })
}

function Index(){
    return(
        <FatherComponent>
            <ChildrenComponent />
            {(fatherProps)=><ChildrenComponent {...fatherProps} name={'最帅的男人'}/>}
        </FatherComponent>
    );
}


最终展示效果:

  • 我的名字叫zxy
  • i am react
  • 我的名字叫最帅的男人
  • i am react

props的使用:

1、混入

import React, { useEffect } from 'react';

function ChildComponent(props){
    useEffect(()=>{
        console.log(props) // 此处打印 props fatherProps的参数
    },[])
    return(
        <div>我的父级组件混入了两个props</div>
    )
}

function FatherComponent(props){
    const fatherProps ={
        name: 'zxy',
        age: 18,
    };
    return(
        <ChildComponent {...props} {...fatherProps} /> // 混入两个props
    )
}

function Index(){
    const rootProps ={
        height: 178cm,
        weight: 75kg,
    };
    return(
        <FatherComponent {...rootProps}/>
    )
}

2、抽离:

import React, { useEffect } from 'react';

function ChildComponent(props){
    useEffect(()=>{
        console.log(props) // 此处打印 没有 remark
    },[])
    return(
        <div> i am zxy </div>
    )
}

function FatherComponent(props){

    const {remark, ...otherProps} = props;
    return(
        <ChildComponent {...otherProps} /> // 混入两个props
    )
}

function Index(){
    const rootProps ={
        name: 'zxy',
        age: 18,
        height: 178cm,
        weight: 75kg,
        remark: '此处是要被抽离开的参数',
    };
    return(
        <FatherComponent {...rootProps}/>
    )
}

其他:

function ChildComponent(){return <div>子组件</div>}

function FatherComponent(){return <ChildComponent name='zxy' age=18 />}