ReactP7_React的组件化开发(二)_super(props)传值问题_组件通信子传父_Context

这边是react学习记录,期间加入了大量自己的理解,用于加强印象,若有错误之处还请多多指出

关于super(props)的传值问题

props打印情况不同

正常情况下,需要super(props)方法来获取传入此组件的参数。如图所示,super( )方法并没有去主动获取props中的参数,所以在随后的console.log(this.props)中打印出来的是undefined,但是在render函数中,却可以获得props值,获取值和super( )没有关系。这个原因,需要从源码中去解读。框架不论我们是否主动获取并赋值this.props值,都会在运行的过程中进行一次对this.props的赋值操作,因此在随后是可以直接使用传过来的props参数的。具体代码的位置在如图所示的代码中
赋值代码

组件通信子传父

某些情况,我们也需要子组件向父组件传递消息:

在vue中是通过自定义事件来完成的——this.$emit([自定义事件名])

在React中同样是通过props传递消息,只是让父组件给子组件传递一个回调函数,在子组件中调用这个函数即可

个人理解来看,就是告诉子组件一些信息“A={func}”,其中A是发生的事件名称,func是发生该事件之后需要执行的事情,或者说需要执行的函数,子组件如果需要了,就会在发生指定的情况之后执行以下A,那么就会在父组件根据A触发的情况,执行以下func。和vue不同的是,vue是子组件告诉父组件发生了事情A,然后在A执行func,React是父组件告诉子组件A和func,然后子组件发生并使用了A,对应的调用了父组件之前给的的func

Appjs代码

import React,{ Component } from "react";
import Child from "./Child"

export default class App extends Component{
    constructor(props){
        super();
        this.state = {
            counter:0
        }
        
    }
    
    render(){
        const {counter} = this.state;
        return (
            <div>
                <h2>{counter}</h2>
                <Child add = { e=>{this.Increment()}}/>
            </div>
        )
    }

    Increment(){
        this.setState({
            counter:this.state.counter + 1,
        })
    }
}

Childjs代码

import React , {Component} from "react";

export default class Child extends Component{
    constructor(props){
        super(props);
        this.state = {

        }
    }

    render(){
        const { add } = this.props;
        return(
            <button onClick={add}>+1</button>
        )
    }
}

通俗的讲:此处就是父组件写了方法Increment,并且告诉子组件,发生add事件的话我就会执行Increment,子组件在发生点击事件之后,告诉父组件,发生了add事件需要执行Increment,此时父组件执行了一次Increment函数。基本就是这么个思路

组件通信案例

tab效果

制作一个类似于tab的点击显示效果:直接上代码

App.js

import React,{ Component } from "react";
import TabControl from "./TabControl"


export default class App extends Component{
    constructor(props){
        super();
        console.log(this.props);//undefined
        this.state = {
            titles:["A","B","C"],
            currentIndex:0,
        }
        
    }
    
    render(){
        console.log(this.props);//{}
        const { titles, currentIndex } = this.state;
        return (
            <div>
                <TabControl itemClick={ index => { this.itemClick(index) }} titles={titles}/>
                <h2>{titles[currentIndex]}</h2>
            </div>
        )
    }

    itemClick(index){
        this.setState({
            currentIndex:index
        })
    }
}

tabControl.js

import React from "react";
import PropTypes from "prop-types"

export default class TabControl extends React.Component{
    constructor(props){
        super(props);
        this.props = props;
        this.state = {
            currentIndex : 0,
        }
    }

    render(){
        const { titles } = this.props;
        const { currentIndex } = this.state;
        return (
            <div className="tab-control">
                {
                    titles.map((item,index)=>{
                        return(
                            <div key={item} 
                                 className={"tab-item " + (index === currentIndex?"active":"")} 
                                 onClick={ e => { this.itemClick(index) }}>
                                <span>{item}</span>
                            </div>
                        )
                    })
                }
            </div>
        )
    }

    itemClick(index){
        this.setState({
            currentIndex:index,
        })

        const { itemClick } = this.props;
        itemClick(index);
    }
}

TabControl.propTypes = {
    titles:PropTypes.array,
    currentIndex:PropTypes.number,
}

style.css

*{
    margin: 0;
    padding: 0;
}
.tab-control{
    display: flex;
    text-align: center;
    height: 44px;
    line-height: 44px;
}
.tab-item{
    flex: 1;
}
.tab-item span{
    padding: 8px 5px;
}
.tab-item.active span{
    border-bottom: solid 2px red;
}

通过这个案例,基本能够掌握组件通信了,而且这个难度的练习基本能够应付很多的tab功能需求

Context

这一块说实话很烦,我也记不太住,大致理解成有那么一个框框,这个框框表示的是那些可以被共享的参数,那些被框框给框住的组件,是可以访问到这些共享参数的,具体执行有兴趣可以往下看

背景:常见的数据传递方式是通过props属性自上而下(由父到子)进行传递,但是一些数据需要在多个组件中进行共享。如果在顶层的App中定义这些信息,一层层传递下去,那么对于一些中间组件不需要数据的组件来说,是一种冗余的操作

Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props,Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据。

简而言之就是提供一种平台,能够存放供所有组件共同读取的数据,类似Vuex里面$store.state青春版

React.createContext

  • 创建一个需要共享的Context对象

如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值

defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值

个人理解:创建一个共享数据的框框, 共享的默认数据使用defaultValue存放

创建Context对象

Context.Provider

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化

Provider 接收一个 value 属性,传递给消费组件

一个 Provider 可以和多个消费组件有对应关系

多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据

当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染

个人理解,这里面存放的就是框框内部需要共享的数据

Provider示例
这里的"…"只是表示需要输入的是数据

Class.contextType

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象

这能让你使用 this.context 来消费最近 Context 上的那个值

你可以在任何生命周期中访问到它,包括 render 函数中

给类组件重新赋值并创建Context

Context.Consumer

这里React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context

这里需要 函数作为子元素(function as child)这种做法

这个函数接收当前的 context 值,返回一个 React 节点

consumer就是框框里面需要调用数据的组件,需要套在Provider的里面,通过回调函数来对数据进行调用

调用者
以上就是组件化开发第二部分的全部内容了

感谢coderwhy(王红元老师)的课程指导

爱生活,爱猪猪

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值