React (三) 修改props,React父传子、子传父、this绑定

什么是 props

props 可以看成一个对外的接口,用来接收外部传入的数据。组件中主要有两种属性 propsstate 无论 props 或者 state 中哪两个发生了改变都会重新引发渲染

如何使用

如果你使用过 Vue,也肯定使用过父传子和子传父的功能,在 react 中也有父子通信。

父传子

函数组件

上一篇文章我讲述了使用[...props] 来进行传值,那是一种简写。

// 父组件
function Component1(){
    // 创建一个ref
    const porps = {name: 'ccc',age:18};
  	const a = {h: 'ccc'};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <User {...porps} />    {/* 使用简写 */}
            <User name='我没有用简写' age='18' />
              {/* 如果是非字符串 就要用大括号*/}
						<User name='我没有用简写' age='18' title={a}/>
        </div>
    );
}
// 通过参数去接受值
function User(props){
    return(
        <div>
            <h2>我是user组件</h2>
            <p>{props.name}---{props.age}</p>
        </div>

    );
}

上面的代码中就是简写和非简写的区别。可以直接在组件编写属性的方式传参数,在用 props 去接收参数。

我们都知道react在没有 hook 之前他们两个的区别主要在于有无 state 和生命周期,类组件可以使用生命周期和构造函数,而函数组件中只有 props,函数组件也称为无状态组件。类组件如果有 state 就是有状态组件,没有 state 就是无状态组件。如果类组件没有 state 推荐使用函数组件(函数组件效率高于类组件)。有了 hook 之后 在函数组件组件里面也可以使用 state

类组件

类组件中如何传值

// 定义一个函数组件和写内联样式
// 父组件
function Component1(){
    // 创建一个ref
    const porps = {name: 'ccc',age:18};
  	const a = {h: 'ccc'};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <User {...porps} />    {/* 使用简写 */}
            <User name='我没有用简写' age='18' />
              {/* 如果是非字符串 就要用大括号*/}
						<User name='我没有用简写' age='18' title={a}/>
        </div>
    );
}

// 类组件 props 被实例化了 可以直接使用this.去访问之后在结构
class Footer extends React.Component {
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{name}---{age}</h1>
            </div>
        );
    }
}

默认值

可以通过 defaultProps 设置默认值

// 父组件
function Component1(){
    // 创建一个ref
    const porps = {name: 'ccc',age:18};
  	const a = {h: 'ccc'};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            
            <User/>
              {/* 如果是非字符串 就要用大括号*/}
						<User name='我没有用简写' age='18' title={a}/>
        </div>
    );
}

// 子组件
function User(props){
    return(
        <div>
            <h2>我是user组件</h2>
            <p>{props.name}---{props.age}</p>
        </div>

    );
}

User.defaultProps = {
    age: 20,
    name: 'xxx'
};

子传父

props 可以接受任意类型的值。我们可以利用这个特性来实现子组件到父组件的传值,我们可以传递一个函数,通过函数传参的方式,来实现这一功能。这里使用的 this 绑定方式这里查看介绍

// 父组件
function Component1(){
    // 创建一个ref
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    function getData(data){
        console.log('我是接受接受到子组件的值', data);
    }
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} getData={getData} ref={userRef}></Footer>
        </div>
    );
}


// 子组件
class Footer extends React.Component {
    constructor(props){
        super(props);
        // 组件内部的状态 通过 setState 方法来更改的
        this.state = {
            name1:props.name+'ttt',
            num: 0
        };
    }
    add = () => {
        this.setState(state =>({
            num: ++state.num,
        }));
        this.props.getData(this.state.num);
    }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
                <button onClick={this.add}>点我加一{this.state.num}</button>
            </div>
        );
    }
}

修改 props

在 React 中我们不能直接修改 props

// 子组件
function User(props){
  props.name = 'ttt';
    return(
        <div>
            <h2>我是user组件</h2>
            <p>{props.name}---{props.age}</p>
        </div>

    );
}
// 第三行报错

上面的代码会报错,props 是个只读属性。在 react 中数据流是单向的,不能改变一个组件在渲染是传进来的 props。因为组件会复用,如果可以修改 props,结果会不可预测,也违背了组件的设计原则,但是这并不代表在 props 不能修改**。**

可以通过 state 来变相修改 props。state 可以理解为中间人,主要是利用了 react 里面的重新渲染(setState)方式把props传入到组件中,在通过赋值到 state,在来修改。

// 父组件
function Component1(){
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} ref={userRef}></Footer>
        </div>
    );
}

// 子组件
class Footer extends React.Component {
  // constructor是构造器函数,如果没有申明,会自动添加,而且只会执行一次
  constructor(props){
  	super(props);
    // 组件内部的状态 通过 setState 方法来更改的
    this.state = {
    	name1:props.name+'ttt'
    }
  }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
            </div>
        );
    }
}

constructor 里面除了修改 props 还可以进行函数绑定

// 父组件
function Component1(){
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} ref={userRef}></Footer>
        </div>
    );
}

// 子组件
class Footer extends React.Component {
    constructor(props){
        super(props);
        // 组件内部的状态 通过 setState 方法来更改的
        this.state = {
            name1:props.name+'ttt',
            num: 0
        };
        this.add = this.add.bind(this);
    }
    add(){
        this.setState(state =>({
            num: ++state.num,
        }));
    }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
                <button onClick={this.add}>点我加一{this.state.num}</button>
            </div>
        );
    }
}

事件监听 this 绑定

this 一共有四种绑定方式,一种就是我上面说的在 constructor 使用 bind 绑定。而且这种方法也是官方推荐的。

下面我来介绍其他三种

直接在 jsx 元素上进行绑定(不推荐)

// 父组件
function Component1(){
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} ref={userRef}></Footer>
        </div>
    );
}

// 子组件
class Footer extends React.Component {
    constructor(props){
        super(props);
        // 组件内部的状态 通过 setState 方法来更改的
        this.state = {
            name1:props.name+'ttt',
            num: 0
        };
    }
    add(){
        this.setState(state =>({
            num: ++state.num,
        }));
    }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
                <button onClick={this.add.bind(this)}>点我加一{this.state.num}</button>
            </div>
        );
    }
}

上面代码中我们直接在 button 上进行了绑定。但是这样子会出现一个问题,就是每次在渲染组件的时候,都会创建一个新的函数。会造成额外的渲染,影响性能。

箭头函数(推荐)

使用了 ES6 的类字段

// 父组件
function Component1(){
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} ref={userRef}></Footer>
        </div>
    );
}

// 子组件
class Footer extends React.Component {
    constructor(props){
        super(props);
        // 组件内部的状态 通过 setState 方法来更改的
        this.state = {
            name1:props.name+'ttt',
            num: 0
        };
    }
    add = () => {
        this.setState(state =>({
            num: ++state.num,
        }));
    }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
                <button onClick={this.add}>点我加一{this.state.num}</button>
            </div>
        );
    }
}

因为箭头函数本身没有 this 属性,所以他的 this 指向的是 Footer 这个类本身,这个方法是推荐的因为不会存在多重绑定的问题。

直接在 jsx 上使用箭头函数(不推荐)

// 父组件
function Component1(){
    const userRef = React.createRef();
    const porps = {name: 'ccc',age:18};
    return (
        <div style={divStyles} title={divTitles} className="App" tab-index="1">
            <Footer {...porps} ref={userRef}></Footer>
        </div>
    );
}

// 子组件
class Footer extends React.Component {
    constructor(props){
        super(props);
        // 组件内部的状态 通过 setState 方法来更改的
        this.state = {
            name1:props.name+'ttt',
            num: 0
        };
    }
    add = () => {
        this.setState(state =>({
            num: ++state.num,
        }));
    }
    render() {
        const {name,age} =this.props;
        return(
            <div>
                <h1>我是一个类组件{this.state.name1}---{age}</h1>
                <button onClick={() => {
                    this.setState(state =>({
                        num: ++state.num,
                    }));
                }}>点我加一{this.state.num}</button>
            </div>
        );
    }
}

直接在 jsx 上使用箭头函数会导致和直接在 jsx 上进行绑定一样的问题就是每次在渲染组件的时候,都会创建一个新的函数。会造成额外的渲染,影响性能。事件只要是在 render 上绑定事件都会出现性能问题。

React子组件可以通过将父组件的函数作为props传递给子组件来绑定点击事件。在子组件中,可以通过调用父组件传递的函数来触发父组件中定义的事件处理程序。 在父组件中,定义一个处理点击事件的函数。然后将这个函数作为props传递给子组件。在子组件中,可以通过props访问到父组件传递的函数,然后将这个函数绑定到子组件的点击事件上。 例如,我们有一个父组件Parent和一个子组件Child。在Parent组件中定义一个handleClick函数来处理点击事件,然后将这个函数作为props传递给Child组件。 Parent组件中的代码可以是这样的: ```javascript class Parent extends React.Component { handleClick() { console.log('父组件中的点击事件处理函数'); } render() { return <Child onClick={this.handleClick} />; } } ``` Child组件中的代码可以是这样的: ```javascript class Child extends React.Component { render() { return <button onClick={this.props.onClick}>点击我</button>; } } ``` 在Child组件中,我们将父组件传递的handleClick函数作为props中的onClick属性,然后在button元素的onClick事件中使用this.props.onClick来触发父组件的事件处理程序。 这样,当点击Child组件中的按钮时,就会触发父组件中定义的handleClick函数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [React组件创建与事件绑定](https://blog.csdn.net/u012190388/article/details/128438333)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [React父子组件间方法调用](https://blog.csdn.net/noeal/article/details/115300055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值