React组件进阶

一、组件的props

  • props的作用:接收传递给组件的数据
  • 传递数据,给组件标签添加属性
class App extends React.Component {
    state = {
        userName: 'yusongH'
    }

    render() {
        return (
            <div>
                <ComComponent txt="你好啊" userName={this.state.userName}></ComComponent>
            </div>
        )
    }
}
复制代码
  • 接收数据
    • 函数组件通过参数props接收数据
    function ComComponent(props) {
        return (
            <div>
                <div>txt:{props.txt}</div>
                <div>userName:{props.userName}</div>
            </div>
        )
    }
    复制代码
    • 类组件通过this.porps接收数据
    class ComComponent extends React.Component {
        render() {
            return (
                <div>
                    <div>txt:{this.props.txt}</div>
                    <div>userName:{this.props.userName}</div>
                </div>
            )
        }
    }
    复制代码
  • 总结
    • 可以给组件传递任意类型的数据
    • props是只读的对象,只能读取属性的值,修改会报错
    • 注意点:使用类组件时,如果写了构造函数,应该将props传递给super(),不然无法在构造函数中获取到props
    constructor(props) {
        super(props)
    
        console.log(this.props)
        console.log(props)
    }
    复制代码

三、组件通讯的三种方式

  • 父组件 -> 子组件

    • 给子组件标签添加属性,值为state中的数据
    class App extends React.Component {
        render() {
            return (
                <div>
                    <ComComponent txt="你好啊" userName={this.state.userName}></ComComponent>
                </div>
            )
        }
    }
    复制代码
    • 子组件中通过props接收父组件中传递的数据
    class ComComponent extends React.Component {
        render() {
            return (
                <div>
                    <div>txt:{this.props.txt}</div>
                    <div>userName:{this.props.userName}</div>
                </div>
            )
        }
    }
    复制代码
  • 子组件 -> 父组件

    • 思路:利用回到函数,父组件提供回调,子组件调用回调函数,将需要传递的数据作为回调函数的参数传递过去
    • 注意:获取参数的的回调的this指向问题
    // 父组件
    class ParentComponent extends React.Component {
        state = {
            childMsg: ''
        }
        // 接收传值回调函数
        getChildMsg = (data) => {
            console.log('父组件传递的参数:', data)
            // 注意this的指向,所以要使用箭头函数
            console.log(this)
            this.setState({
                childMsg: data
            })
        }
        render() {
            return (
                <div>
                    <div>父组件</div>
                    <div>子组件传递的数据:{this.state.childMsg}</div>
                    <ChildComponent getMsg={this.getChildMsg}></ChildComponent>
                </div>
            )
        }
    }
    
    // 子组件
    class ChildComponent extends React.Component {
        state = {
            msg: '给父组件的数据data'
        }
    
        handleClick = () => {
            // 调用父组件提供的回调
            this.props.getMsg(this.state.msg)
        }
    
        render() {
            return (
                <div>
                    <div>子组件</div>
                    <button onClick={this.handleClick}>点击传递数据给父组件</button>
                </div>
            )
        }
    }
    复制代码
  • 兄弟组件

    • 状态提升:将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
    • 公共父组件:1、提供共享的状态 2、提供操作这些共享的状态的方法
    • 要通讯的子组件只需要通过props接收状态或者操作状态的方法
    class BrotherComponent extends React.Component {
        state = {
            count: 0
        }
    
        // 提供给子组件修改状态
        changeCount = () => {
            // 修改状态
            this.setState({
                count: this.state.count + 1
            })
        }
    
        render() {
            return (
                <div>
                    <FirstChildComponent count={this.state.count} />
                    <SecondChildComponent changeCount={this.changeCount} />
                </div>
            )
        }
    }
    
    class FirstChildComponent extends React.Component {
        render() {
            return (
                <div>计数器:{this.props.count}</div>
            )
        }
    }
    
    
    class SecondChildComponent extends React.Component {
        handleClick = () => {
            this.props.changeCount()
        }
    
        render() {
            return (
                <button onClick={this.handleClick}>+1</button>
            )
        }
    }
    复制代码

四、Context基本使用

作用:跨组件传值

使用步骤

  • 调用React.createContext()创建Provider(提供数据)和Consumer(消费数据)两个组件
// 创建context,Provider,Consumer
const { Provider, Consumer } = React.createContext()
复制代码
  • 使用Provider组件作为父节点
class ContextComponent extends React.Component {

    render() {
        return (
            // 使用Provider包裹,通过value传值
            <Provider value="hello, child">
                <div>
                    contextComponent
                    <Node />
                </div>
            </Provider>
        )
    }
}
复制代码
  • 设置value属性,表示要传递的数据
class ContextComponent extends React.Component {

    render() {
        return (
            // 使用Provider包裹,通过value传值
            <Provider value="hello, child">
                <div>
                    contextComponent
                    <Node />
                </div>
            </Provider>
        )
    }
}
复制代码
  • 通过Consumer组件接收数据,Consumer组件里面定义回调函数
class Node extends React.Component {
    render() {
        return (
            <div>
                node
                <SubNode />
            </div>
        )
    }
}


class SubNode extends React.Component {

    render() {
        return (
            <div>
                subNode
                <Child />
            </div>
        )
    }
}

class Child extends React.Component {

    render() {
        return (
            // 使用Consumer包裹,定义回调接收数据
            <Consumer>
                {
                    data => <div>child:contextComponet提供的数据 -- {data}</div>
                }
            </Consumer>
        )
    }
}
复制代码

五、porps深入

children属性

  • 表示组件标签的子节点,当组件标签有自节点的时候,props就会有该属性
  • children属性和普通的props一样,值可以为任意值(文本,React元素,组件,函数)
class PropsDeep extends React.Component {

    render() {
        return (
            <div>
                parent
                <Child>子节点</Child>
            </div>
        )
    }
}

class Child extends React.Component {
    render() {
        return (
            <div>
                child ---
                {this.props.children}
            </div>
        )
    }
}
复制代码

props校验

  • 对于组件来说,props是外来的,无法保证组件使用者传入什么格式的数据,所以需要进行校验
  • props校验:允许在创建组件的时候,就指定props的类型、格式等

使用步骤

  • 安装包prop-types(npm i porp-types/yarn add prop-types)
  • 导入prop-types包
  • 使用组件名.propTypes = {}来给组件的props添加校验规则
  • 校验规则通过PropType对象来指定
  • 约束规则
    • 常见类型:array、bool、func、number、object、string
    • React元素类型:element
    • 必传项:isRequired
    • 特定结构的对象:shape({})
    PropsCheck.propTypes = {
        // 属性num的类型:数值(number)
        num: PropTypes.number,
        // 属性fn的类型:函数(func)并且为必传项
        fn: PropTypes.func.isRequired,
        // 属性tag的类型:React元素(element)
        tag: PropTypes.element,
        // 属性obj的类型:对象({userName: 'yusong', age: 18})
        obj: PropTypes.shape({
            userName: PropTypes.string,
            age: PropTypes.number
        })
    }
    复制代码

六、组件的生命周期

只有类组件(有状态组件)才有生命周期

创建时(挂载阶段)

执行时机:组件创建时(页面加载时)

执行顺序:

  • constructor()
    • 创建组件时,最先执行
    • 作用:
      • 初始化state
      • 为事件处理程序绑定this
  • render()
    • 每次组价渲染都会触发
    • 作用
      • 渲染UI(不能调用setState(),不然会导致递归
  • componentDidMount()
    • 组件挂载(完成DOM渲染后)
    • 作用
      • 发送网络请求
      • DOM操作
钩子函数 触发时机 作用
constructor 创建组件时,最先执行 1、初始化state
2、为时间处理程序绑定this
render 每次组价渲染都会触发 渲染UI(不能调用setState(),不然会导致递归
componentDidMount 组件挂载(完成DOM渲染后) 1、发送网络请求
2、DOM操作

更新时(更新阶段)

执行时机:

  • 调用setState()
  • 调用forceUpdate()
  • 组件接收到新的props

执行顺序

  • render()
    • 每次组件渲染都会触发
    • 作用
      • 渲染UI(与挂载阶段是同一个render)
  • componentDidUpdate()
    • 组件更新(完成DOM渲染后)
    • 作用
      • 发送网络请求
      • DOM操作
      • 注意点:如果要setState()必须放在一个if条件中
      class LifeCycle extends React.Component {
          state = {
              count: 0,
          }
          changeCount = () => {
              this.setState({
                  count: this.state.count + 1,
              })
          }
      
          render() {
              return (
                  <div>
                      <Child1 count={this.state.count} />
                      <Child2 changeCount={this.changeCount} />
                  </div>
              )
          }
      }
      
      class Child1 extends React.Component {
          // prevProps上一次的props
          componentDidUpdate(prevProps) {
              console.log('更新完毕', prevProps)
              // 在改钩子里面调用setState()一定要加判断条件,否则会导致递归报错
              // 判断前一次的props是否与当前的props相等
              if (prevProps.count !== this.props.count) {
                  this.setState({})
              }
          }
          render() {
              return (
                  <div>
                      child1:{this.props.count}
                  </div>
              )
          }
      }
      
      class Child2 extends React.Component {
          render() {
              return (
                  <div>
                      child2
                      <button onClick={() => this.props.changeCount()}>+1</button>
                  </div>
              )
          }
      }
      复制代码
钩子函数 触发时机 作用
render 每次组件渲染都会触发 渲染UI(与挂载阶段是同一个render)
componentDidUpdate 组件更新(完成DOM渲染后) 1、发送网络请求
2、DOM操作
3、注意点:如果要setState()必须放在一个if条件中

卸载时(卸载阶段)

执行时机

  • 组件从页面中消失

执行顺序

  • componentWillUnmount
    • 组件卸载(从页面中消失)
    • 作用
      • 执行清理工作(比如:清理定时器等)
钩子函数 触发时机 作用
componentWillUnmount 组件卸载(从页面中消失) 执行清理工作(比如:清理定时器等)

其他的钩子函数介绍(在后面文章再详细介绍)

旧版完整生命周期钩子

image.png

新版版完整生命周期钩子

image.png

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享