React父子组件通信

一、父子组件表单域通信

1.1 受控表单域写法

新建Login.js组件,写入:

import React, { Component } from 'react'

class Filed extends Component {
  render() {
    return <div style={{background: "yellow"}}>
      <label>{this.props.label}</label>
      <input value={this.props.value} type={this.props.type} onChange={(event) => {
        this.props.onChangeEvt(event.target.value)
      }}></input>
    </div>
  }
}

export default class Login extends Component {
  state = {
    name: localStorage.getItem('name') || '',
    password: ''
  }
  render() {
    return (
      <div>
          <h1>登录页面</h1>
          <Filed label="用户名" type="text" onChangeEvt={(value) => {
            console.log(value)
            this.setState({
              name: value
            })
          }} value={this.state.name}></Filed>
          <Filed label="密码" type="password" onChangeEvt={(value) => {
            console.log(value)
            this.setState({
              password: value
            })
          }} value={this.state.password}></Filed>
          <button onClick={() => {
            console.log(this.state,'请求后端登录接口')
          }}>登录</button>
          <button onClick={() => {
            console.log(888)
            this.setState({
              name: '',
              password: ''
            })
          }}>重置</button>
      </div>
    )
  }
}

可以看到我们的Filed组件是子组件,并且是受控的,可以看到在表单域的受控子组件中,这种写法是非常繁琐的。我们先看看效果:
在这里插入图片描述


1.2 ref版表单域组件

接下来我们将用ref表单域写法,新建LoginRef.js组件代码:

import React, { Component } from 'react'

class Filed extends Component {
  state = {
      value: ""
  }
  clear() {
      this.setState({
          value: ""
      })
  } 
  render() {
    return <div style={{background: "yellow"}}>
      <label>{this.props.label}</label>
      <input type={this.props.type} onChange={(event) => {
          this.setState({
              value: event.target.value
          })
      }} value={this.state.value}></input>
    </div>
  }
}

export default class LoginRef extends Component {
  name = React.createRef()
  password = React.createRef()
  state = {
    name: '',
    password: ''
  }
  render() {
    return (
      <div>
          <h1>登录页面</h1>
          <Filed label="用户名" type="text" ref={this.name}></Filed>
          <Filed label="密码" type="password" ref={this.password}></Filed>
          <button onClick={() => {
            console.log(this.name.current.state.value, this.password.current.state.value, '请求登录接口')
          }}>登录</button>
          <button onClick={() => {
            this.name.current.clear()
            this.password.current.clear()
          }}>重置</button>
      </div>
    )
  }
}

可以看到我们将状态定义在了子组件中,并且清空方法也在子组件中,我们在父组件中直接用了 ref来获取到值和重置表单,效果:
在这里插入图片描述


1.3 非父子通信方式

1、状态提升(中间人模式)
React中的状态提升概括来说,就是将多个组件需要共享的状态提升到它们最近的父组件上,在父组件上改变这个状态然后通过props分发给子组件。

创建组件MiddleCp.js写入代码:

import React, { Component } from 'react'
import axios from 'axios'
import '../css/middlecp.css'

export default class MiddleCp extends Component {
  
    constructor() {
        super()
        this.state = {
            filmList: [],
            info: '',
        }
        axios.get('/data.json').then(res => {
            console.log(res.data.data.films)
            this.setState({
                filmList: res.data.data.films
            })
        }, err => {
            console.log(err)
        }) 
    }

  render() {
    return (
      <div>
          {
              this.state.filmList.map(item => {
                  return <FilmItem key={item.filmId} {...item} onEvent={(value) => {
                      console.log('父组件接收', value)
                      this.setState({
                          info: value
                      })
                  }}></FilmItem>
              })
          }
          <FilmDetail info={this.state.info}></FilmDetail>
      </div>
    )
  }
}


class FilmItem extends Component {
    render() {
        let {name, poster, grade, synopsis} = this.props
        return (
          <div className="filmitem" onClick={() => {
              this.props.onEvent(synopsis)
          }}>
              <img src={poster} alt={name}></img>
              <h4>{name}</h4>
              <div>观众评分:{grade}</div>
          </div>
        )
      }
}

class FilmDetail extends Component {
    render() {
        return (
          <div className="filmdetail">
              {this.props.info}
          </div>
        )
      }
}

middlecp.css写入代码:

.filmitem img {
    width: 100px;
    float: left;
    margin-right: 10px;
}

.filmitem {
    overflow: hidden;
    padding: 10px;
}
.filmdetail {
    position: fixed;
    right: 0;
    top: 100px;
    background-color: skyblue;
    width: 300px;
    height: 300px;
}

public文件夹下创建data.json,写入数据。
效果如下:
在这里插入图片描述
完成了中间人传值模式。


1.4 非父子通信(订阅发布模式)

新建组件subscribe.js写入代码:

import React, { Component } from 'react'
import axios from 'axios'
import '../css/middlecp.css'

// 调度中心
var bus = {
    list: [],
    // 订阅
    subscribe(callback) {
        this.list.push(callback)
    },
    // 发布
    publish(text) {
        this.list.forEach(callback => {
            callback && callback(text)
        })
    }
}


export default class Subscribe extends Component {
  
    constructor() {
        super()
        this.state = {
            filmList: [],
        }
        axios.get('/data.json').then(res => {
            console.log(res.data.data.films)
            this.setState({
                filmList: res.data.data.films
            })
        }, err => {
            console.log(err)
        }) 
    }

  render() {
    return (
      <div>
          {
              this.state.filmList.map(item => {
                  return <FilmItem key={item.filmId} {...item}></FilmItem>
              })
          }
          <FilmDetail></FilmDetail>
      </div>
    )
  }
}


class FilmItem extends Component {
    render() {
        let {name, poster, grade, synopsis} = this.props
        return (
          <div className="filmitem" onClick={() => {
            //   console.log(synopsis)
            bus.publish(synopsis)
          }}>
              <img src={poster} alt={name}></img>
              <h4>{name}</h4>
              <div>观众评分:{grade}</div>
          </div>
        )
      }
}

class FilmDetail extends Component {
    constructor() {
        super()
        this.state = {
            info: ""
        }
        bus.subscribe((info) => {
            // console.log(info)
            this.setState({
                info: info
            })
        })
    }
    render() {
        return (
          <div className="filmdetail">
              {this.state.info}
          </div>
        )
      }
}

可以看到我们采用了发布订阅的模式,也完成了非父子组件通信。


1.5 非父子通信context方案

context状态树传参。
创建context.js组件,写入代码:

import React, { Component } from 'react'
import axios from 'axios'
import '../css/middlecp.css'

const GlobalContext = React.createContext(); // 创建context对象

export default class Context extends Component {

    constructor() {
        super()
        this.state = {
            filmList: [],
            info: ""
        }
        axios.get('/data.json').then(res => {
            console.log(res.data.data.films)
            this.setState({
                filmList: res.data.data.films
            })
        }, err => {
            console.log(err)
        })
    }

    render() {
        return (
            <GlobalContext.Provider value={{
                info: this.state.info,
                changeInfo: (value) => {
                    this.setState({
                        info: value
                    })
                }
            }}>
                <div>
                    {
                        this.state.filmList.map(item => {
                            return <FilmItem key={item.filmId} {...item}></FilmItem>
                        })
                    }
                    <FilmDetail></FilmDetail>
                </div>
            </GlobalContext.Provider>
        )
    }
}


class FilmItem extends Component {
    render() {
        let { name, poster, grade, synopsis } = this.props
        return (
            <GlobalContext.Consumer>
                {(value) => {
                    console.log(value)
                    return <div className="filmitem" onClick={() => {
                        value.changeInfo(synopsis)
                    }}>
                        <img src={poster} alt={name}></img>
                        <h4>{name}</h4>
                        <div>观众评分:{grade}</div>
                    </div>
                }}
            </GlobalContext.Consumer>
        )
    }
}

class FilmDetail extends Component {
    render() {
        return (
            <GlobalContext.Consumer>
                {
                    (value) => <div className="filmdetail">
                        {value.info}
                    </div>
                }
            </GlobalContext.Consumer>
        )
    }
}

可以看到我们借用了context状态树来进行非父子同信,不管是怎样的嵌套方式,都可以进行通信。

在学习React的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你华还是你华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值