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

本文详细介绍了React中的Props概念及其使用方法,包括父传子、子传父等通信方式,并讲解了如何设置默认值及修改Props的方法。

什么是 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 上绑定事件都会出现性能问题。

<think> 我们正在处理一个关于React类组件中如何从子组件向组件传递数据的问题。 根据引用内容,我们可以总结出以下关键点: 1. 组件需要定义一个回调函数(例如storeId),这个函数将接收来自子组件的数据。 2. 组件通过props将这个回调函数传递给子组件(例如<Sub storeId={this.storeId} ... />)。 3. 子组件通过props获取到这个回调函数,并在适当的时候(比如某个事件发生时)调用这个函数,将数据作为参数传递给它。 现在,我们将按照这个步骤来展示一个完整的示例,包括组件和子组件的代码。 注意:用户要求的是类组件的实现方式,所以我们使用类组件来编写。 步骤: 1. 组件(Parent)中定义状态(state)和回调函数(例如handleDataFromChild)。 2. 将回调函数通过props传递给子组件(Child)。 3. 子组件中,通过this.props获取到传递过来的回调函数,并在需要的时候调用它,传递数据。 下面是一个具体的代码示例。 组件(Parent.js): ```jsx import React, { Component } from 'react'; import Child from './Child'; // 假设子组件为Child.js class Parent extends Component { constructor(props) { super(props); this.state = { // 组件的状态 parentData: null }; // 为了在回调函数中使用this,需要绑定this(如果不使用箭头函数) this.handleDataFromChild = this.handleDataFromChild.bind(this); } // 定义回调函数,用于接收子组件传递的数据 handleDataFromChild(data) { // 在这里处理从子组件接收到的数据 console.log('从子组件接收到的数据:', data); // 更新组件的状态 this.setState({ parentData: data }); } render() { return ( <div> <h1>组件</h1> <p>从子组件接收到的数据:{this.state.parentData}</p> {/* 将回调函数通过props传递给子组件 */} <Child onDataSend={this.handleDataFromChild} /> </div> ); } } export default Parent; ``` 子组件(Child.js): ```jsx import React, { Component } from 'react'; class Child extends Component { constructor(props) { super(props); this.state = { childData: '这是来自子组件的数据' }; // 绑定this this.sendDataToParent = this.sendDataToParent.bind(this); } // 子组件中的方法,用于向组件传递数据 sendDataToParent() { // 调用组件传递过来的回调函数,并将子组件的数据作为参数传递 this.props.onDataSend(this.state.childData); } render() { return ( <div> <h2>子组件</h2> <button onClick={this.sendDataToParent}>传递数据给组件</button> </div> ); } } export default Child; ``` 说明: 1. 组件Parent定义了一个回调函数handleDataFromChild,并将其通过props(属性名为onDataSend)传递给子组件Child。 2. 子组件通过this.props.onDataSend获取到这个回调函数,并在按钮点击事件中调用它,同时将子组件状态中的childData作为参数传递。 3. 组件的回调函数被调用后,会更新组件的状态parentData,并在页面上显示出来。 注意:在构造函数中绑定this是确保在回调函数中能够正确使用this的常见做法。也可以使用箭头函数来避免绑定,例如在组件中直接使用箭头函数定义回调函数: ```jsx handleDataFromChild = (data) => { // ... 函数体 } ``` 这样就不需要在构造函数中绑定了。 以上就是在React类组件中实现子组件向组件传值的方法。 根据要求,生成相关问题: §§相关问题§§ 1. 在React函数组件中如何实现子组件向组件传值? 2. 除了回调函数,React还有哪些方式可以实现组件间的数据传递? 3. 为什么在React中需要绑定回调函数的this?如何避免? 4. 在子组件向组件传值的过程中,如何避免不必要的渲染? </think>在 React 类组件中,子组件向组件传递数据主要通过回调函数机制实现。以下是完整实现步骤和代码示例: ### 实现步骤 1. **组件定义回调函数** 组件创建一个方法(如 `handleDataFromChild`)用于接收子组件数据 2. **组件传递回调给子组件** 通过 props 将回调函数传递给子组件(如 `<Child onData={this.handleDataFromChild}>`) 3. **子组件调用回调函数** 子组件通过 `this.props` 获取回调函数,在需要时调用并传入数据 4. **组件处理数据** 组件的回调函数接收到数据后更新状态或执行其他操作 ### 完整代码示例 **组件 (Parent.js)** ```jsx import React, { Component } from 'react'; import Child from './Child'; class Parent extends Component { constructor(props) { super(props); this.state = { receivedData: null }; } // 定义接收子组件数据的回调函数 handleDataFromChild = (childData) => { console.log('收到子组件数据:', childData); this.setState({ receivedData: childData }); }; render() { return ( <div> <h2>组件</h2> <p>收到子组件数据:{this.state.receivedData}</p> {/* 传递回调函数给子组件 */} <Child onDataSend={this.handleDataFromChild} /> </div> ); } } export default Parent; ``` **子组件 (Child.js)** ```jsx import React, { Component } from 'react'; class Child extends Component { state = { inputValue: '' }; // 数据变更处理 handleChange = (e) => { this.setState({ inputValue: e.target.value }); }; // 向组件提交数据 submitToParent = () => { // 调用组件传递的回调函数 this.props.onDataSend(this.state.inputValue); }; render() { return ( <div> <h3>子组件</h3> <input type="text" value={this.state.inputValue} onChange={this.handleChange} /> <button onClick={this.submitToParent}>传递数据到组件</button> </div> ); } } export default Child; ``` ### 关键实现说明 1. **回调函数绑定** 使用箭头函数确保 `this` 指向正确(`handleDataFromChild = () => {}`) 2. **数据流方向** 子组件通过 `this.props.onDataSend(data)` 触发组件函数 3. **状态更新** 组件在回调中通过 `setState()` 更新界面 4. **Props 验证** 建议添加 PropTypes 确保类型安全: ```jsx import PropTypes from 'prop-types'; Child.propTypes = { onDataSend: PropTypes.func.isRequired }; ``` ### 应用场景 1. 表单组件提交数据到容器 2. 列表项向组件传递选中状态 3. 模态框组件返回用户操作结果 4. 自定义控件值变更通知
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值