超级详细react笔记(七)组件传值篇

1 引入

  • 组件之间需要传值
    • 父传子 通过绑定
    • 子传父 通过方法
    • 兄弟之间传值 通过父为中间键
    • 指定传值 context
  • 组件之间传值需要过滤
    • 使用PropTypes

2 传值

在这里插入图片描述

2.1 父传子

  • children
    在这里插入图片描述

2.1.1 文件

  • 父组件绑定<Children title={this.state.msg}/>
  • 子组件接受<div>我是子组件====={this.props.title}</div>
    在这里插入图片描述
convert/children.js
import React ,{Component}from 'react'
export default class Children extends Component {
    constructor() {
        super();
    }

    render() {
        return (
            <div>我是子组件====={this.props.title}</div>
        )
    }
}
component/index.js
  • 优雅暴露所有组件
export {default as Children} from './convert/children'
APP.js
  • index.js的入口文件
import React,{Component} from 'react'
import {Children} from './components'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            msg:'我是父组件的值'
        }
    }
    render() {
        return(
            <div>
                <Children title={this.state.msg}/>
            </div>
        )
    }
}

在这里插入图片描述

2.1.2 总结

  • 使用父组件绑定值,子组件默认props接收

2.1.3 children属性

获取传来的内容

  • APP.js
import React,{Component} from 'react'
import {Children} from './components'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            msg:'我是父组件的值'
        }
    }
    render() {
        return(
            <div>
                <Children>
                    <div>我是DIV</div>
                </Children>
            </div>
        )
    }
    getSon=(data)=>{
        console.log(data)
    }
}
  • children.js
import React ,{Component}from 'react'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
        }
    }

    render() {
        return (
            <div>我是子组件 1
                <h1>{this.props.children}</h1>
            </div>
        )
    }
}

在这里插入图片描述

2.2 子传父

  • 思路:使用方法传值
  • 父组件绑定方法(可传参数)
  • 子组件接收父组件方法,当调用时将数据作为参数传给父组件
    在这里插入图片描述

2.2.1 基础写法

  • APP.js
import React,{Component} from 'react'
import {Children} from './components'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            msg:'我是父组件的值'
        }
    }
    render() {
        return(
            <div>
                <Children title={this.state.msg}
                 myData={this.getSon}/>
            </div>
        )
    }
    getSon=(data)=>{
        console.log(data)
    }
}
  • children.js
import React ,{Component}from 'react'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
            data:'我是子组件的值'
        }
    }

    render() {
        return (
            <div>我是子组件====={this.props.title}
            <button onClick={this.setData}>传值</button></div>
        )
    }
    setData=()=>{
        this.props.myData(this.state.data)
    }
}

2.2.2 优雅式写法

  • APP.js
import React,{Component} from 'react'
import {Children} from './components'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            msg:'我是父组件的值'
        }
    }
    render() {
        return(
            <div>
                <Children title={this.state.msg}
                 myData={this.getSon}/>
            </div>
        )
    }
    getSon=(data)=>{
        console.log(data)
    }
}

  • children.js使用了ES6的结构解析(结构赋值)
import React ,{Component}from 'react'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
            data:'我是子组件的值'
        }
    }

    render() {
        return (
            <div>我是子组件====={this.props.title}
            <button onClick={this.setData}>传值</button></div>
        )
    }
    setData=()=>{
        const { myData} =this.props
        myData(this.state.data)
    }
}

在这里插入图片描述

2.3 兄弟之间传值(上两者结合)

  • 核心:以父组件为中间键 即所有事件和属性在父组件身上
    • 业务逻辑在父组件上
    • 子组件触发
  • 思路:
    • 子组件1得到父组件的值(父传子)
    • 子组件2得到父组件的方法(调用父组件方法,改变值,在父组件中执行)

2.3.1 子组件1得到父组件的值

在这里插入图片描述

2.3.2 子组件2得到父组件的值和方法

在这里插入图片描述

2.3.3 实现

  • APP.js
import React,{Component} from 'react'
import {Children,Children2} from './components'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            step:2,
            count:0
        }
    }
    render() {
        return(
            <div>
                <Children title={this.state.count}/>
                <Children2
                    add={this.add}
                    step={this.state.step}
                />
            </div>
        )
    }
    add=()=>{
        this.setState(state=>{
            return {
                count:state.count+=state.step
            }
        })
    }
}

  • children.js
import React ,{Component}from 'react'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
        }
    }

    render() {
        return (
            <div>我是子组件 1
                <h1>{this.props.title}</h1>
            </div>
        )
    }
}

  • children2.js
import React ,{Component}from 'react'
export default class Children2 extends Component {
    constructor() {
        super();
        this.state={
        }
    }

    render() {
        return (
            <div>我是子组件 2
                <hr/>
                <button onClick={this.change}>点我</button>
            </div>
        )
    }
    change=()=>{
        const {step,add} = this.props
        add(step)
    }
}

2.3.4 预览

在这里插入图片描述

2.4 指定组件传值

  • 使用``

2.4.1 基本写法

  • 流程:

    • 爷爷组件通过传值给父亲组件state,父亲props得到爷爷组件值传给孙子组件,孙子组件调用props
      在这里插入图片描述
  • APP.js

import React,{Component} from 'react'
// 爷爷组件
class Grandpa extends Component{
    constructor() {
        super();
        this.state={
            msg:'爷爷的红包来了'
        }
    }
    render() {
        return(
            <div> 爷爷组件<Father msg={this.state.msg} /></div>
        )
    }
}
// 父亲组件
class Father extends Component{
    constructor(props) {
        super(props);

    }
    render() {
        return(
            <div>父亲组件<Son msg={this.props.msg} />
            </div>
        )
    }


}
// 孙子组件
class Son extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div>孙子组件======={this.props.msg}</div>
        )
    }
}
export default class APP extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div><Grandpa/></div>
        )
    }
}

2.4.2 使用Context写法

  • const {Provider,Consumer} =React.createContext()
  • 不通过父亲组件
  • 思路:
    • 定义:const {Provider,Consumer} =React.createContext()
    • 源组件:<Provider value={this.state.msg}> <div>爷爷组件<Father/></div></Provider>
    • 目标组件:<Consumer> { data=>{ return <h1>{data}</h1> } } </Consumer> 一个箭头函数
import React,{Component} from 'react'
const {Provider,Consumer} =React.createContext()
// 爷爷组件
class Grandpa extends Component{
    constructor() {
        super();
        this.state={
            msg:'爷爷的红包来了'
        }
    }
    render() {
        return(
             <Provider value={this.state.msg}> <div>爷爷组件<Father/></div></Provider>
        )
    }
}
// 父亲组件
class Father extends Component{
    constructor(props) {
        super(props);

    }
    render() {
        return(
            <div>父亲组件<Son/>
            </div>
        )
    }


}
// 孙子组件
class Son extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div>
                <Consumer>
                    {
                        data=>{
                            return <h1>{data}</h1>
                        }
                    }
                </Consumer>
            </div>
        )
    }
}
export default class APP extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div><Grandpa/></div>
        )
    }
}

在这里插入图片描述

2.4.3 优化封装(组件化)

  • const {Provider,Consumer} =React.createContext()
  • 单独封装的原因:
    • Provider 爷爷组件使用,Consumer孙子组件使用,这两个组件都调用时,将创建两次,
    • 不是同一个createContext()对象,孙子组件将得不到值
      在这里插入图片描述
target文件
  • grandpa.js
import React,{Component} from 'react'
import {Provider} from '../createContext'
import Father from './father'
export default class Grandpa extends Component{
    constructor() {
        super();
        this.state={
            msg:'爷爷的红包来了'
        }
    }
    render() {
        return(
            <Provider value={this.state.msg}> <div>爷爷组件<Father/></div></Provider>
        )
    }
}

  • father.js
import React,{Component} from 'react'
import Son from "./son";
export default class Father extends Component{
    constructor(props) {
        super(props);
    }
    render() {
        return(
            <div>父亲组件<Son/>
            </div>
        )
    }
}
  • son.js
import React,{Component} from 'react'
import {Consumer} from '../createContext'
export default class Son extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div>
                <Consumer>
                    {
                        data=>{
                            return <h1>{data}</h1>
                        }
                    }
                </Consumer>
            </div>
        )
    }
}
createContext()文件
import React from 'react'
const {Provider,Consumer} =React.createContext()
export {
    Provider,
    Consumer
}
APP.js
import React,{Component} from 'react'
import {Grandpa} from './components'
export default class APP extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div><Grandpa/></div>
        )
    }
}

2.5 过滤

  • 使用依赖prop-types
  • 作用:保证其他组件传进来的值是该组件想要的

2.5.1 安装依赖

yarn add prop-types

2.5.2 使用依赖

  • 引入依赖import PropTypes from 'prop-types'
  • 使用依赖Children.propTypes={ title:PropTypes.number }
  • children.js
import React ,{Component}from 'react'
import PropTypes from 'prop-types'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
            data:'我是子组件的值'
        }
    }

    render() {
        return (
            <div>我是子组件====={this.props.title}
            <button onClick={this.setData}>传值</button></div>
        )
    }
    setData=()=>{
        const { myData} =this.props
        myData(this.state.data)
    }
}

Children.propTypes={
    title:PropTypes.number
}

2.5.3 预览

在这里插入图片描述

2.5.4 推荐写法

1 无状态组件(外部)
import React ,{Component} from 'react'
import PropTypes from "prop-types";
export default function Rfc (props){
    return(
        <div>无状态组件
            {props.title}
        </div>
    )
}
Rfc.propTypes={
    title:PropTypes.number
}

在这里插入图片描述

2 有状态组件(static)
  • 在外部也可以使用(违背了类的面向对象编程)
import React ,{Component}from 'react'
import PropTypes from 'prop-types'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
            data:'我是子组件的值'
        }
    }
    static propTypes={
        title:PropTypes.number
    }
    render() {
        return (
            <div>我是子组件====={this.props.title}
            <button onClick={this.setData}>传值</button></div>
        )
    }
    setData=()=>{
        const { myData} =this.props
        myData(this.state.data)
    }
}

2.5.5 其他控制

  • 控制必填项
  • 控制默认值
1 控制必填项
import React ,{Component}from 'react'
import PropTypes from 'prop-types'
export default class Children extends Component {
    constructor() {
        super();
        this.state={
            data:'我是子组件的值'
        }
    }
    static propTypes={
        title:PropTypes.string.isRequired
    }
    render() {
        return (
            <div>我是子组件====={this.props.title}
            <button onClick={this.setData}>传值</button></div>
        )
    }
    setData=()=>{
        const { myData} =this.props
        myData(this.state.data)
    }
}

在这里插入图片描述

2 控制默认值
  • 控制默认值
有状态组件
 static defaultProps={
        title:'崽崽'
    }
无状态组件
Rfc.propTypes={
    title:PropTypes.string
}
Rfc.defaultProps={
    title:"再砸"
}

3 拓展

3.1 购物车实现

3.1.1 基本实现

  • 思路:
    • 1 使用map将数据遍历,渲染到页面
    • 2 将数据结构搭建好
    • 3 为- + 两个按钮帮上id
    • 4 为按钮绑定点击事件
      • 点击时map 循环,判断是否与目标的id相等e.target.dataset.id
      • 如果相等,将el.id执行操作,并且修改总价
    • 5 购物车总价实现
      • 定义一个临时变量temp,遍历forEach 算出每一个总价 加到temp
      • 在每次- + 时调用,async + await
      • 在生命周期中完成首次渲染componentDidMount
        在这里插入图片描述
import React,{Component} from 'react'

export default class Cart extends Component{
    constructor() {
        super();
        this.state={
            allPrice:0,
            carts:[{
                id: 1,
                name: '足球鞋',
                price: 25,
                count: 1,
                total: 25
            }, {
                id: 2,
                name: '篮球鞋',
                price: 35,
                count: 1,
                total: 35
            }, {
                id: 3,
                name: '草鞋',
                price: 125,
                count: 1,
                total: 125
            }]
        }
        this.reduce=this.reduce.bind(this)
        this.add=this.add.bind(this)
    }
    componentDidMount() {
        this.getAll()
    }

    render() {
        return(
            <div>
                <ul>
                    {
                        this.state.carts.map(el=><li key={el.id}>
                        <h1 >{el.name}</h1>
                         <h3><span>价格:${el.price}</span>
                             <button onClick={this.reduce}  data-id={el.id}>-</button>
                             <input value={el.count} readOnly/>
                             <button onClick={this.add} data-id={el.id}>+</button>
                             <span>总价:{el.total}</span>
                         </h3>
                    </li>)}
                    <h1>总价:{this.state.allPrice}</h1>
                </ul>
            </div>
        )
    }
    async reduce(e){
      await  this.setState({
            carts: this.state.carts.map(el=>{
                if(el.id===Number(e.target.dataset.id)) {
                    el.count--
                    el.total=el.count*el.price
                }
                return el
            })
        })
        this.getAll()

    }
    async add(e){
        await  this.setState({
            carts: this.state.carts.map(el=>{
                if(el.id===Number(e.target.dataset.id)) {
                    el.count++
                    el.total=el.count*el.price
                }
                return el
            })
        })
        this.getAll()

    }
    getAll(){
        let  temp = 0
        this.state.carts.forEach(el=>{
            temp +=el.count*el.price
        })
        this.setState({
            allPrice:temp
        })
    }
}

3.1.2 组件化实现

  • 分析:
    • 1 每一项数据都是一个子组件
    • 2 子组件可以对自己的值进行修改(可控组件)
    • 3 涉及组件之间传值
      • 父组件给子组件传数据(遍历)
      • 子组件接收方法,控制父组件的总价
  • 思路:
    • 1 创建每一项为子组件
    • 2 创建父组件
      • 定义数据,方法,
        在这里插入图片描述
  • carts.js
import React,{Component} from 'react'
import CartItem from "./cartItem";
export default class Carts extends Component{
    constructor() {
        super();
        this.state={
            allPrice:0,
            carts:[{
                id: 1,
                name: '足球鞋',
                price: 25,
                count: 1,
                total: 25
            }, {
                id: 2,
                name: '篮球鞋',
                price: 35,
                count: 1,
                total: 35
            }, {
                id: 3,
                name: '草鞋',
                price: 125,
                count: 1,
                total: 125
            }]
        }
    }
    render() {
        return(
            <div>
                {this.state.carts.map(el=> <CartItem {...el}
                                                     add={this.add}
                                                     reduce={this.reduce}
                                                     all={this.getAll}
                                                     key={el.id}/>)}
                <h1>总价:{this.state.allPrice}</h1>
            </div>
        )
    }
    add=(id)=>{
       this.setState({
           carts: this.state.carts.map(el=>{
               if(id===el.id){
                   el.count++
               }
               return el
           })
       })
    }
    reduce=(id)=>{
        this.setState({
            carts: this.state.carts.map(el=>{
                if(id===el.id){
                    el.count--
                }
                return el
            })
        })
    }
    getAll=()=>{
        let temp =0
        this.state.carts.map(el=>{
            temp+=el.price*el.count
        })
        this.setState({
            allPrice:temp
        })
    }
}

  • cartItem.js
import React,{Component} from 'react'
export default class CartItem extends Component{
    constructor() {
        super();
        this.reduce=this.reduce.bind(this)
        this.add=this.add.bind(this)
    }
    componentDidMount() {
        this.props.all()
    }

    render() {
        return(
            <div>
                <ul>
                    {
                        <li>
                            <h1>{this.props.name}</h1>
                            <h3><span>价格:${this.props.price}</span>
                                <button onClick={this.reduce} >-</button>
                                <input value={this.props.count} readOnly />
                                <button onClick={this.add} >+</button>
                                <span>总价:{this.props.price*this.props.count}</span>
                            </h3>
                        </li>}
                </ul>
            </div>
        )
    }
    async reduce(){

        await this.props.reduce(this.props.id)
        this.props.all()
    }
   async add(){
       await  this.props.add(this.props.id)
        this.props.all()
    }
}

3.2 温度转换实现

  • 分析:
    • 父组件绑定值,定义要改变的方法,子组件触发
    • 子组件触发时,传入ID
    • 两个子组件child1 child2,一个父组件APP
      在这里插入图片描述

children1.js

import React ,{Component}from 'react'
export default class Children1 extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div>
                <fieldset>
                    <legend>输入温度,摄氏温度:</legend>
                    <input type="text" onChange={this.change} value={this.props.s}/>
                </fieldset>
            </div>
        )
    }
    change=(e)=>{
        this.props.sChange(e.target.value)
    }
}

children2.js

import React,{Component} from 'react'
export default class Children2 extends Component{
    constructor() {
        super();
    }
    render() {
        return(
            <div>
                <fieldset>
                    <legend>输入温度,华氏温度:</legend>
                    <input type="text" value={this.props.h} onChange={this.change} />
                </fieldset>
            </div>
        )
    }
    change=(e)=>{
        this.props.hChange(e.target.value)
    }
}

APP.js

import React,{Component} from 'react'
import {Child1,Child2} from './components/index'
export default class APP extends Component{
    constructor() {
        super();
        this.state={
            s:0,
            h:32,
            flag:true
        }
        this.sChange=this.sChange.bind(this)
    }
    render() {
        return(
            <div>
                <Child1 s={this.state.s} sChange={this.sChange} />
                <Child2 h={this.state.h} hChange={this.hChange}/>
                <h1>{this.state.flag?'水还没有沸腾':'水沸腾了'}</h1>
            </div>
        )
    }
   async  sChange(value){
      await  this.setState(state=>{
            return {
                s:value ,
                h:32+Number(value)*1.8,
            }
        })
       if( Number(this.state.h)>100){
           this.setState({
               flag:false
           })
       }else {
           this.setState({
               flag:true
           })
       }
    }
    hChange=(value)=>{
        this.setState({
            h:value,
            s:(Number(value)-32)/1.8
        })
        console.log(this.state.h)
    }
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值