React中父子组件通信

本篇文章我们来学习组件之间的通信,继续以上篇文章中提到的 添加并展示商品列表 为案例,将其功能复杂化为一个小购物车案例,即拆分一个购物车列表的子组件,跟购物车父组件进行通信。

父组件传值给子组件,通过 props 传值

1.在 src -> components 文件夹中,新建子组件 Cart.js ,我们创建基于类的子组件,父组件传过来的值通过 this.props 调用中,具体代码如下:

import React, { Component } from 'react';
// 基于类的组件
export default class Cart extends Component {
    render() {
        return (
            <table>
                <tbody>
                    {this.props.list.map(item  => (
                        <tr key={item.id}>
                            <td>名称:{item.name}</td>
                            <td>数量:{item.count}</td>
                        </tr>
                    ))}
                </tbody>
            </table>
        );
    }
}

上面的代码中我们给出的是基于类的组件的传值方式,如果你更习惯于函数类型的组件创建,那在函数中直接使用属性传过来的值即可,具体代码如下:

import React, { Component } from 'react';
//  函数类型的组件
export function Cart({list}){
    return (
        <table>
            <tbody>
                {list.map(item  => (
                <tr key={item.id}>
                    <td>名称:{item.name}</td>
                    <td>数量:{item.count}</td>
                </tr>
                ))}
            </tbody>
        </table>
    )
}

2.打开 src -> components -> CartSample.js 文件,导入上一步创建的 Cart 组件,并通过 props 传值,同时在商品列后新增 加购 按钮,点击实现加入购物车效果,并展示在页面,具体代码实现如下:

import React, { Component } from 'react';
// 基于类的组件 导入方式
import Cart from './Cart';
// 函数类型的组件 导入方式
// import { Cart } from './Cart';

export default class CartSample extends Component {
    //  状态的初始化一般放在构造器中
    constructor(props){
        super(props);
        this.state = {
            text: '',
            goods: [],
            cartList: []
        }
        this.textChange = this.textChange.bind(this)
    }
    // 当 input 的值 text 发生变化的时候,我们让 textChang 去切换 input 的值
    textChange (event){
        this.setState({text: event.target.value})
    }
    addGoods = () => {
        this.setState(prevstate => {
            // react 官方希望传入与返回的对象不应该是同一个对象
            return {
                goods: [
                    ...prevstate.goods,
                    {
                        id: prevstate.goods.length + 1,
                        name: prevstate.text
                    }
                ]
            }
        })
    }
    // 加购
    addToCart = (good) => {
        // 创建一个新的购物车列表
        const newCartList = [ ...this.state.cartList ]
        // 根据 商品ID 判断购物车内有无传入的商品
        const idx = newCartList.findIndex( c => c.id === good.id)
        // 找到该 idx 对应的商品
        const item = newCartList[idx]
        if(item){
            // 如果购物车内有该商品,则商品数量 +1
            // 删除 idx 项,再新增一项,新增项的属性和 item 一样,唯独修改 count
            newCartList.splice(idx,1,{ ...item,count: item.count +1 })
        }else{
            // 如果购物车内没有该商品
            newCartList.push({...good,count:1})
        }
        //更新
        this.setState({cartList:newCartList})
    }
    render() {
        return (
            <div>
                {/* 事件处理 */}
                <div>
                    <input type="text" value={this.state.text} onChange={this.textChange}/>
                    <button onClick={this.addGoods}>加入商品</button>
                </div>
                <h1>商品列表</h1>
                <ul>
                   {this.state.goods.map((good) => (
                       <li key={good.id}>
                            {good.name}
                            {/* 新增 加购按钮 */}
                            <button onClick={() => this.addToCart(good)}>加入购物车</button>
                        </li>
                   ))}
                </ul>
                {/* 购物车 */}
                <h1>购物车列表</h1>
                 {/* 通过 list 属性吧购物车列表传给 cart 组件 */}
                <Cart list={this.state.cartList}></Cart>
            </div>
        );
    }
}

子组件传值给父组件

React 中子组件想传值给父组件,是父组件把回调函数直接通过 属性的方式传给子组件,称之为状态提升,即把子组件的状态提升出来,派发到父组件上,告诉子组件数据发生变化时应该调用哪个函数,那要怎么实现呢?
1.继续以上面的代码为例,新增子组件中商品的数量可以加减的需求,那就要求我们把修改子组件 Cart.js 的代码,在数量 count 标签前后新增 -+ 的按钮,把原先 tr 标签中的代码改成如下:

<td>名称:{item.name}</td>
<td>数量:
    <button onClick={() => minus(item)}>-</button>
        {item.count}
    <button onClick={() => add(item)}>+</button>
</td>

2.打开 src -> components -> CartSample.js 文件,在原有代码的基础上修改以下代码:

// 新增函数,处理数量的更新
add = (good) =>{
    const newCartList = [ ...this.state.cartList ]
    const idx = newCartList.findIndex( c => c.id === good.id)
    const item = newCartList[idx]
    // 点击 + 按钮其实就是购物车内有该商品,然后该商品数量 +1
    newCartList.splice(idx,1,{ ...item,count: item.count +1 })
    this.setState({cartList:newCartList})
}
minus = (good) =>{
    const newCartList = [ ...this.state.cartList ]
    const idx = newCartList.findIndex( c => c.id === good.id)
    const item = newCartList[idx]
    // 点击 + 按钮其实就是购物车内有该商品,然后该商品数量 -1
    newCartList.splice(idx,1,{ ...item,count: item.count -1 })
    this.setState({cartList:newCartList})
}

{/* 原本 cart 标签新增 add 和 minus 属性 */}
<Cart list={this.state.cartList} add={this.add} minus={this.minus}></Cart>

其实上面的重复代码有很多,是可以优化的,下面我们来做一下优化:

// Cart.js 中修改 + - 按钮的点击事件
<td>数量:
    <button onClick={() => this.props.countChange(item)}>-</button>
        {item.count}
    <button onClick={() => this.props.countChange(item,1)}>+</button>
</td>

// CartSample.js 中删除 add 和 minus 函数,新增 countChange
countChange = (good,type) =>{
    const newCartList = [ ...this.state.cartList ]
    const idx = newCartList.findIndex( c => c.id === good.id)
    const item = newCartList[idx]
    // 购物车列表中肯定有该商品,因为不需要判断 item 是否存在,只需要对 count 进行操作即可
    if(type){// 有 type 即是 点击 + 按钮,商品数量 +1
        newCartList.splice(idx,1,{ ...item,count: item.count +1 })
    }else{ // 否则就是点击 - 按钮,商品数量 -1
        newCartList.splice(idx,1,{ ...item,count: item.count -1 })
    }
    this.setState({cartList:newCartList})
}
{/* 删除 add 和 minus 函数,新增 countChange 的属性*/}
<Cart list={this.state.cartList} countChange={this.countChange}></Cart>

原文地址:https://www.cnblogs.com/-muzi/p/11964825.html

时间: 2024-08-25 04:54:25

React中父子组件通信的相关文章

Vuejs——(10)组件——父子组件通信

版权声明:出处http://blog.csdn.net/qq20004604 目录(?)[+] 本篇资料来于官方文档: http://cn.vuejs.org/guide/components.html#u7236_u5B50_u7EC4_u4EF6_u901A_u4FE1 本文是在官方文档的基础上,更加细致的说明,代码更多更全. 简单来说,更适合新手阅读 (二十七)父子组件通信 ①访问子组件.父组件.根组件: this.$parent    访问父组件 this.$children   访问子

从$emit 到 父子组件通信 再到 eventBus

故事还是得从$emit说起,某一天翻文档的时候看到$emit的说明 触发当前实例上的事件?就是自身组件上的事件呗,在父子组件通信中,父组件通过props传递给子组件数据(高阶组件可以用provide和inject),由于这是单向数据流,为了保证复用组件的的时候出现数据错乱. 那么只能通过在子组件里面去触发一个事件,来让父组件自己更新数据. 那么问题来了,$emit不是说好的触发当前实例上的事件吗?那是怎么去能触发父组件数据更新的呢?难道父组件里也能$on对应的事件??? 其实不是的,看下面这个示

父子,子父,非父子组件通信

父子组件通信 父亲的数据给子集 父组件向子组件传值 ??? 子组件在props中创建一个属性,用于接收父组件传过来的值: ??? 父组件 引入子组件-->注册子组件-->引用子组件: ??? 在子组件标签中添加子组件props中创建的属性: ??? 将所要传递的值赋值给该属性. props: prop类型:通常你希望每个prop都有指定的数据类型,你可以以对象的形式列出prop,对象的属性的名称和值分别对应了prop的值和类型. 单向数据流:所有的prop都使得其父子prop形成一个单向数据流

Vue中的组件通信

这两天在学Vue,记录一下我认为比较重要的东西 Vue中的组件通信: 我们可以分为3个步骤来: 1.声明局部子组件,简称 "声子", 2.挂载到dom树上面去,简称:"挂子" 3.进行使用,简称:"用子" 上面写的别人可能看不太明白,毕竟只是我的看法: <body> <div id="app"> </div> </body> 先写一个div,给它一个ID=app <scri

react初探(二)之父子组件通信、封装公共组件

一.前言 在组件方面react和Vue一样的,核心思想玩的就是组件,下面举两个组件常用的情景. 场景一:假如我们现在有一个页面包含表格以及多个弹框,这种时候如果将这个页面的业务代码写在一个组件中,那么这一块的代码会看着非常恶心.如果这个时候我们将这个页面的表格以及弹框这些单独的模块分别写成组件的形式,然后再在这个页面中将这些组件引入进来,那样我们的代码会看着非常整洁.这样做会需要使用到父子组件之间的通信,下面会详细解释. 场景二:日常项目中我们会经常遇到某一个功能会在不同地方使用,但是每次使用的

vue 2 使用Bus.js进行兄弟(非父子)组件通信 简单案例

vue2中废弃了$dispatch和$broadcast广播和分发事件的方法.父子组件中可以用props和$emit().如何实现非父子组件间的通信,可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,之后通过分别调用Bus事件触发和监听来实现组件之间的通信和参数传递. 首先需要在任意地方添加一个bus.js 在bus.js里面 写入下面信息 1 import Vue from 'vue' 2 export default new Vue; 在需要通信的组件都引入B

Vue父子组件通信实践

组件(Component)是Vue.js的核心部分,组件的作用域是孤立的,所以不能在子组件模板内直接引用父组件的数据,但是组件之间的通信是必不可少的.组件A在其模板中使用了组件B,A组件要向B组件传递数据,B组件要将其内部发生的事情告知A组件,那么A.B组件怎么进行通信呢? Vue.js父子组件的关系可以总结为props down,events up,父组件通过props向下传递数据给子组件,子组件通过events给父组件发送消息,它们的工作方式如下图所示: 父组件 - 子组件:父组件传值给子组

vue学习之父子组件通信两种方法

初学vue,最常用及实用的就是父子组件之间的通信了,在此记录一点自己的学习过程 方法一:props及$emit 父组件中先引入子组件,然后components里面注册组件,然后template里调用,调用的时候通过v-bind传递值给子组件,v-on监听子组件$emit传递过来的值 子组件中先用props接收父组件的传值,注意子组件中不可直接修改父组件的传值,可通过watch监听来赋值,通过$emit来传递值给父组件 方法二:ref 父组件传值props方法不变,父组件可通过使用ref来调用子组

React的父子组件生命周期

父子组件生命周期: “生命周期”细想之下有点浪漫主义色彩,不知道是不是从lifecycle英译过来的.作为一个前端从业者,如果让我来取,可能会取成“渲染周期”之类的,毕竟是和浏览器打交道的职业,浏览器的layout使dom树具有骨架,paint则让整个页面光亮起来. React 的一切都是组件,通过 React.createElement 方法来创建嵌套层级,说白了在内存中构建对象树,据此渲染到浏览器中成为dom树,这个时候一个节点是什么时候真正渲染到页面中就变得重要起来,因为只有这个时候你才能