最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • React中组件间的通信方式

    正文概述 掘金(moonlightop)   2021-03-03   610

    特别注意

    • 通过学习React组件间的通信方式,笔者总结以下两个重要的知识点
      • 高层级传递给低层级—高层级用非函数
        • 如:父传子
      • '' 低层级传递给高层级 ''—高层级用函数(callback)
        • 如:子传父

    props

    • 传递数据的对象是一般组件,倾向于父子组件间

    React中组件间的通信方式

    
    import React, { Component } from 'react'
    {/* 
      1. Props组件传递函数给Son1组件 
      2. Son1组件添加用户后调用传递过来的函数,通过setState()修改Props组件的状态
      3. Props组件重新调用render生命周期函数,然后将更新后的状态传递给Son2组件进行渲染
    */}
    
    {/* Props组件负责存储状态 */}
    export default class Props extends Component {
      
      state = {
        users: [
          {name: "hao",age: 20,id: "1"},
          {name: "moon",age: 21,id: "2"},
        ]
      }
      // 传递给Son1组件的回调函数
      updateState = (newUser) => {
        // 将获取到Son1组件调用此函数的参数进行相应的更新
        this.setState({
          users: [...this.state.users,newUser]
        })
      }
    
      render() {
        return (
          <div>
            {/* Son1组件负责添加一个用户 */}
            <Son1 updateState={this.updateState}/>
            {/* Son2组件负责渲染所有用户 */}
            <Son2 users={this.state.users}/>
          </div>
        )
      }
    }
    
    class Son1 extends Component {
    
      nameRef = React.createRef()
      ageRef = React.createRef()
    
      addUser = () => {
        let name = this.nameRef.current.value
        let age = this.ageRef.current.value
        let id = "3"
        this.props.updateState({
          name,
          age,
          id
        })
      }
    
      render() {
        return (
          <div>
            姓名:<input type="text" name="name" ref={this.nameRef}/>
            年龄:<input type="text" name="age" ref={this.ageRef}/>
            <button onClick={this.addUser}>添加一名用户</button>
          </div>
        )
      }
    }
    
    class Son2 extends Component {
      render() {
        // console.log(this.props)
        return (
          <div>
            <ul>
              {
                this.props.users.map(ele => {
                  return <li key={ele.id}>{ele.name}-{ele.age}</li>
                })
              }
            </ul>
          </div>
        )
      }
    }
    
    • 而且父组件可以通过ref来获取到子组件的vdom,从而得到子组件的实例对象
    import React,{ Component } from 'react'
    {/*
      1. Ref组件通过jsx标签的ref属性来获取Son组件的实例对象
      2. 然后就可以在Ref组件中使用Son组件的变量和方法
    */}
    export default class Ref extends Component {
        
      render() {
        return (
          <div>
            <h1>父组件</h1>
            <Son ref={cNode => (this.componentExample = cNode)}/>    
          </div>
        )
      }
      
      componentDidMount() {
        let {state,sonFunc} = this.componentExample
        let {data} = state
        alert(`父组件查看子组件数据:${data}`)
        sonFunc()
      }
      
    }
    
    class Son extends Component {
      
      state = {
        data: 'sonCompoent'
      }
      sonFunc = () => {
        alert('父组件调用子组件的函数(sonFunc)')
      }
    
      render() {
        return (
          <h1>子组件</h1>
        )
      }
    }
    
    

    消息订阅与发布

    • 倾向于兄弟组件(非嵌套组件)
      • 如:PubSubJS
        • 接受数据的组件 订阅消息
        • 传输数据的组件 进行相应的消息发布
        • 订阅消息的组件 卸载时执行的componentWillUnmount函数体内取消订阅

    Context

    • 使用同一个Context对象,由Provider提供数据给它包裹的所有组件-即Consumer
      • 所有组件均可,倾向于跨级组件
      • 最好用一个单独文件导出创建的Context对象
    // 1. 创建并导出Context对象
    import React from 'react'  
    export const MyContext = React.createContext("defaultValue")
    
    import { MyContext } from './MyContext'
    export default class Context extends Component {
      
      state = {
        msg: "Context-倾向于跨级传递或兄弟组件"
      }
    
      render() {
        return (
          <div>
          {/* 2. 用Provider包裹需要渲染的跨级组件 */}
            <MyContext.Provider value={this.state.msg}>
              <ContextSon/>
            </MyContext.Provider>
          </div>
        )
      }
    }''
    class ContextSon extends Component {
      
      render() {
        return (
          <ContextSonSon/>
        )
      }
    
    }
    
    • 接收数据的组件为class component
    class ContextSonSon extends Component {
      // 声明此静态属性并接收context后才能获取
      static contextType = MyContext
    
      render() {
        return (
          <div>
            <h4>
              <span>用this.context获取:{this.context}</span>
              <hr/>
              <span>用Consumer获取:</span>
              <MyContext.Consumer>
                {
                  value => (<span>{value}</span>)
                }
              </MyContext.Consumer>
            </h4>
          </div>
        )
      }
    
    }
    
    • 接收数据的组件为function component
    function ContextSonSon() {
      return (
        <div>
          <h4>
            <span>用Consumer获取:</span>
            <MyContext.Consumer>
              {
                value => (<span>{value}</span>)
              }
            </MyContext.Consumer>
          </h4>
        </div>
      )
    }
    

    RenderProps

    render

    • 子组件中预留组件,而此预留组件由父组件来确定并将子组件传递的数据给此预留组件(React)
      • Vue-Slot
    import React, { Component } from 'react'
    
    export default class RenderProps extends Component {
      render() {
        return (
          <div>
            <Son render={(data)=>(<OtherComponent msg={data}/>)}/>
          </div>
        )
      }
    }
    
    class Son extends Component {
      
      state = {
        msg: `Son组件预留一个组件位置,
              RenderProps组件来确定需要渲染的组件并获取Son组件传递过来的信息(Vue-Slot)`
      }
    
      render() {
        return (
          <div>
            <h3>-Son</h3>
            {this.props.render(this.state.msg)}
          </div>
        )
      }
    }
    
    // 不是比Son组件层级高的组件的 其它组件
    class OtherComponent extends Component {
      render() {
        return (
          <h3>
            - OtherComponent<br/>
            -- {this.props.msg}
          </h3>
        )
      }
    }
    

    children

    • 利用 this.props.children 存储一般组件的文体内容
      
    
    import React, { Component } from 'react'
    
    export default class RenderProps extends Component {
      render() {
        return (
          <div>
            <h3>利用children属性,Son组件不能给OtherComponent传递数据,但仍然预留了一个组件等待RenderProps组件来确定</h3>
            <Son>
              <OtherComponent/>
            </Son>
          </div>
        )
      }
    }
    
    class Son extends Component {
      
      render() {
        return (
          <div>
            <h3>Son</h3>
            {this.props.children}
          </div>
        )
      }
    }
    
    // 不是比Son组件层级高的组件的 其它组件
    class OtherComponent extends Component {
      render() {
        return (
          <h3>
            OtherComponent
          </h3>
        )
      }
    }
    

    redux

    • 集中式管理状态,此处不详细介绍它了,推荐查看react-redux和redux的官方文档
      • 倾向于跨级组件间需要共享状态

    参考

    • 尚硅谷react
    • React ref的前世今生
    • ps:该文章如有不足之处,还望之处,笔者会尽力修改它

    起源地下载网 » React中组件间的通信方式

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元