react语法从入门到项目实战系列(3)-组件通讯与组件进阶

前言

时间过得太快 一晃就入行前端开发三年了,从入行至今做过各种框架的项目,其中主流的react很久没用了,最近刚好复习了一下顺便做成文章分享一下也方便自己日后回忆,有开发经验的前端看完这个系列的文章已经足够参与普通管理系统项目的编写了(包含了class写法的hooks写法)

适用人群: 没时间去看官方学习或者找视频进行系统学习,但又临时接手react项目需要快速上手的的小伙伴;或者会vue框架但想快速多学一门框架方便日后上手的小伙伴

注意: 该文章适合有开发经验的小伙伴观看,如果什么前端框架都不会看的很蒙的

正文

上一章主要讲react的组件基础,这是使用这个框架最核心部分之一,接下来就是学习组件通讯和部分进阶了,毕竟代码都是组件化的,以下会对父子、兄弟和爷孙组件的通讯进行举例讲解

1、父传子

scala 复制代码
//App是父组件,Son是子组件------------父传子
import React from "react";
//函数式组件的Son----------------------------------------------------
function SonF(props) {  //function SonF({msg,child}) {可以这样直接解构使用时直接使用
  //props是一个对象,里面存着父组件传过来的所有数据
  // console.log(props.msg);  //我是父组件呢
  return (
    <div>我是函数组件{props.child}</div>
  )
}

//类组件的Son------------------------------------------------------
class SonC extends React.Component{
  render(){
    return(
      // 类组件直接this.props.msg即可使用父组件传过来的内容
      <div>我是类子组件,{this.props.msg}</div>
    )
  }
}

class App extends React.Component{
  state = {
    message:'我是父组件内容'
  }
  render(){
    return(
      <>
      {/*父传子: 子组件身上绑定属性 属性名称可以自定义 保持语义化 */}
        <SonC msg={this.state.message}></SonC>
        <SonF msg={this.state.message} child={<span style={{color:'red'}}>我是传过去的JSX</span>}></SonF>
      </>
    )
  }
}
export default App;

父组件直接用msg={this.state.message}进行绑定;函数子组件用props.msg进行接收;class子组件用this.props.msg进行接收;其中第31行和第8行的{props.child}这种写法能把带个标签传过去使用
props注意说明 :

1.根据单向数据流要求,子组件只读props中的数据,不能修改

2.可传任意数据 ---- 包括函数和JSX

2、子传父

javascript 复制代码
//--子传父:子组件调用父组件传递过来的函数,并把想要传递的数据当成函数的实参
import React from "react";
//函数式组件的子组件----------------------------------------------------
function SonF(props) {   
  const {sonEvent} = props  //3.把父组件的函数解构出来
  return (
    // 4.子组件函数触发父组件的函数实现子传父效果
    <div>我是函数组件<button onClick={()=>sonEvent('函数子组件传给父亲的内容')}>点击</button></div>
  )
}

//类组件的子组件------------------------------------------------------
class SonC extends React.Component{
  render(){
    return(
      <div>我是类子组件<button onClick={()=>this.props.sonEvent('类子组件传给父亲的内容')}>点击</button></div>
    )
  }
}

class App extends React.Component{
  state = {
    message:'我是父组件内容'
  }
  sonEvent=(a)=>{   //1.父组件准备一个函数
    console.log(a);
  }
  render(){
    return(
      <>
        <SonC sonEvent={this.sonEvent}></SonC>
        {/* 2.父传子把函数给到子组件 */}
        <SonF sonEvent={this.sonEvent}></SonF>
      </>
    )
  }
}
export default App;

按上面行25、32、5、7的标注顺序进行操作; 具体思路就是:父组件定义一个方法 => 然后父传子把方法给子组件 => 子组件触发这个方法传给父组件内容

3、兄弟组件传值

javascript 复制代码
//兄弟组件传值:通过状态提升机制,利用共同的父组件实现兄弟通信
import React from "react";

function SonA(props) {   
  console.log(props.msg);   //4.A组件收到B组件传出去的数据
  return (
    <div>我是组件A</div>
  )
}

function SonB(props) {   
  const msg = '这是B组件传出去的数据'
  return (
    // 1.子B传给父--------------------------------------------------
    <div>我是组件B<button onClick={()=>props.getSon(msg)}>点击</button></div>
  )
}

class App extends React.Component{
  state = {
    sendA:''  //子B传父后,父传子A的中间变量
  }
  getSon = (a) =>{
    //2.父接收后赋值给中间变量----------------------------------------------
    this.setState({
      sendA:a
    })
  }
  render(){
    return(
      <>
      {/* 3.父再传给子A -----------------------------------*/}
        <SonA msg={this.state.sendA}></SonA>
        <SonB getSon={this.getSon}></SonB>
      </>
    )
  }
}
export default App;

按上面行14、24、32、5的标注顺序进行操作; 具体思路就是:组件B把内容传给父组件 => 父组件把内容赋值给中间变量 => 父组件把B组件传来的数据父传子传给组件A

4、爷孙传值

javascript 复制代码
//爷孙传值   App=>SonA=>ComB    实现App的数据直接传给B
import React,{createContext} from "react";  //1.引入createContext方法-------------------
//2.执行createContext方法,解构出需要用的Provider , Consumer--------------------------------
const {Provider , Consumer} = createContext()
function SonA(props) {   
  return (
    <div>我是儿子组件内容<ConB></ConB></div>
  )
}

function ConB(){
  return(
    <>
      {/* 4,通过Consumer使用数据,value =>是固定写法----------------------------------------------- */}
      <div>我是孙子组件内容</div>
      <Consumer>
        {value =>{value}}
      </Consumer>
    </>
  )
}


class App extends React.Component{
  state = {
    msg:'我是传送出去的数据' 
  }
  render(){
    return(
      //3.使用Provider包着根组件,传递的数据写在value(固定写法)处----------------------------------
      <Provider value={this.state.msg}>
        <div>
          <SonA></SonA>
        </div>
      </Provider>
      )
  }
}
export default App;

按上面行1、2、30、14的标注顺序进行操作; 具体思路就是 :引入createContext方法,并且执行createContext方法,解构出需要用的Provider , Consumer => 使用Provider包着根组件(爷组件),传递的数据写在value(固定写法 )处 => 孙组件通过Consumer使用数据,value =>是固定写法
注意: 上面爷组件的value={this.state.msg}和 孙组件{value =>{value}}中,value是固定写法

5、使用举例

javascript 复制代码
import React from "react";  

function SonA({list,delItem}) {   
  return (
     <div>
       {list.map(item=>(
          <div key={item.id}>
            <p>电影名称:{item.name}</p>
            <p>价格:{item.price}</p>
            <p>简介:{item.info}</p>
            {/* 子传父实现删除功能 */}
            <button onClick={()=>delItem(item.id)}>删除</button>
            <hr></hr>
          </div>
        ))} 
     </div>
  )
}


class App extends React.Component{
  state={
    list:[
      {id:1,name:'监狱风云',price:'19.9',info:'一场男人之间的斗争'},
      {id:2,name:'监狱风云2',price:'39.9',info:'一场男人之间的斗争不止'},
      {id:3,name:'监狱风云3',price:'29.9',info:'经典归来,重温岁月时光'},
    ]
  }
 delItem = (id) =>{  //实现删除的函数
    this.setState({
      list:this.state.list.filter(item=>item.id!=id)
    })
  }
  render(){
    return(
      <>
      {/* 父传子把list给子组件处理 */}
        <SonA list={this.state.list} delItem={this.delItem}></SonA>
      </>
      )
  }
}
export default App;

6、组件生命周期

javascript 复制代码
import React from "react";  
class App extends React.Component{
  state={
    count:0
  }
  sumDu = () =>{
    this.setState({
      count:this.state.count+1
    })
  }
  constructor(){
    super()
    console.log('constructor');
  }
  componentDidUpdate(){  // 更新阶段生命周期
    console.log('componentDidUpdate');
  }
  componentDidMount(){  //挂载阶段顺序,类似于vue的mounted,重要---------------------
    console.log('componentDidMount');
  }
  render(){ // 挂载阶段和更新阶段都会触发
    console.log('render');
    return(
      <div>{this.state.count} <button onClick={this.sumDu}>点击</button></div>
      )
  }
}
export default App;

注意 :只有类组件才有生命周期类组件是过期的写法,所以这里教部分生命周期足够项目使用即可没必要深入学习,具体顺序:挂载时--->更新时--->卸载时
挂载阶段顺序

constructor 初始化只执行一次 作用:1.初始化state 2.创建Ref 3.使用bind解决this指向等

render 每次渲染都会触发 作用:渲染UI(注意:不能在里面调用setState()

componentDidMount 完成渲染后执行,初始化时执行一次 作用:发送网络请求,DOM操作
更新阶段:

render 同上 componentDidUpdate DOM渲染完毕 作用:DOM操作,可以获取更新后的DOM(注意:不能在里面调用setState()
卸载阶段

componentWillUnmount 组件卸载时(从页面消失) 作用:执行清理工作,例如清理定时器

7、进阶之-特殊的children属性

javascript 复制代码
import React from "react";  
/*  一。children
      1.可以是函数或者JSX
      2.目的:高阶组件
*/ 
function SonA({children}) {   
  console.log(children); //一个数组
  return (
     <div>
      我是子组件
      {/* 下行会显示:我看看children  我是div  我是Jsx*/}
      {children}  
     </div>
  )
}


class App extends React.Component{

  render(){
    return(
      <>
        <SonA>
          {/* 子组件包着写东西时,那边可以获取到children这个属性,包含包着的所有内容 */}
          <p>我看看children</p>
          <div>我是div</div>
          {<h1>我是Jsx</h1>}
        </SonA>
      </>
      )
  }
}
export default App;

行23处父亲组件使用子组件SonA时,在里面SonA /SonA中间写了内容,在子组件SonA用children能获取到

小结

这一节熟悉组件之间的通讯,这个部分是项目实战中必不可少的部分,后面将会讲解比较重要的函数组件具体用法也就是hooks,看完下节真的就能直接写页面了

相关推荐
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
老码沉思录1 小时前
React Native 全栈开发实战班 - 第四部分:用户界面进阶之动画效果实现
react native·react.js·ui
奔跑草-8 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
林太白14 小时前
❤React-React 组件通讯
前端·javascript·react.js
豆华15 小时前
React 中 为什么多个 JSX 标签需要被一个父元素包裹?
前端·react.js·前端框架
前端熊猫15 小时前
React第一个项目
前端·javascript·react.js
练习两年半的工程师15 小时前
使用React和Vite构建一个AirBnb Experiences克隆网站
前端·react.js·前端框架
林太白15 小时前
❤React-JSX语法认识和使用
前端·react.js·前端框架
女生也可以敲代码15 小时前
react中如何在一张图片上加一个灰色蒙层,并添加事件?
前端·react.js·前端框架