React 高级API用法 Context&Refs转发

React 高级API用法

1、Context

前言

react 中组件数据传递是通过props属性 单向传递的,但当组件层级过多时组件数据传递会变繁琐。Context允许数据隔代传递,而不必显式的通过组件树逐层传递props。从而使局部数据“共享”。

使用场景

  • 父组件用Provider生产数据,子组件使用Consumer消费数据
  • 父组件用Provider生产数据,组件使用ContextType接收数据(只用于类组件)
  • 动态和静态Context(父组件更新Context,被Provider包裹的子组件刷新数据,没被Provider包裹的子组件使用Context默认值)
  • 在嵌套组件中更新Context(子组件通过Context传递的函数更新数据)
  • 消费多个Context (createContext多个Context对象父组件通过Provider 层层嵌套子组件,子组件通过Consumer 层层嵌套取数据)

ProductContext.js:创建的Context组件文件
ProviderPage.js:父组件(数据生产者)
MiddlePage.js:中间组件
ConsumerPage.js:子组件(数据消费者)
GrandSonPage.js:子组件(数据消费者)

场景1:父组件用Provider生产数据,子组件使用Consumer消费数据

src\page\context\part_1\ProviderPage.js

场景2:父组件用Provider生产数据,组件使用ContextType接收数据(只用于类组件 因为需要使用static)

作用:contextType 可以简化 context 的使用,不使用 consumer 也可以共享变量
src\page\context\part_2\ProviderPage.js

场景3:动态和静态Context(父组件更新Context,被Provider包裹的子组件刷新数据,没被Provider包裹的子组件使用Context默认值)

作用:contextType 可以简化 context 的使用,不使用 consumer 也可以共享变量
src\page\context\part_3\ProviderPage.js

场景4:在嵌套组件中更新Context(子组件通过Context传递的函数更新数据)

子组件通过调用父组件context中的函数 通知父组件更新状态 从而达到子传父组的效果
src\page\context\part_4\ProviderPage.js

场景5:消费多个Context (createContext多个Context对象父组件通过Provider 层层嵌套子组件,子组件通过Consumer 层层嵌套取数据)

父组件中通过多层嵌套 将context 传入子组件 使数据更有层次

2、Refs转发

###什么是refs
Refs 是一个 获取 DOM节点或 React元素实例的工具。在 React 中 Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素。

创建 Refs
1、React.createRef() 【React >=16.3】

这种方式既可以在函数组件中使用,也可以在class组件中使用。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
    componentDidMount() {
        console.log(this.myRef)
        console.log(this.myRef.current)
    }
  render() {
    return <div ref={this.myRef}>React.createRef()</div>
  }
} 
2、React.useRef() 【React >=16.8】

这种只可以在函数组件中使用。

const App = ()=>{
    const myRef = React.useRef(null)
    //const myRef = React.createRef() 两种创建 ref 对象的方式都可以
    React.useEffect(()=>{
        console.log(myRef)
        console.log(myRef.current)
    },[]) //模拟生命周期
    return (
        <div ref={myRef}>React.useRef()</div>
    )
}
3、回调 Refs
const App = () => {
  // 初始化定义ref
  let myRef = null;
  // 初始化定义ref
  React.useEffect(() => {
      console.log(myRef)
      console.log(myRef.current)
  }, []) //模拟生命周期
  return (
      <div ref={(ref) => myRef = ref} >回调 Refs</div>
  )
}


class App extends React.Component {
  constructor(props) {
      super(props);
  }
  componentDidMount() {
      console.log(this.myRef)
      console.log(this.myRef.current)
  }
  render() {
      return <div ref={ref => this.myRef = ref}>React.createRef()</div>
  }
}
  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底DOM 元素作为其 current 属性。
  • 当 ref 属性用于 class 组件时,ref 对象的current属性为组件实例对象 。
  • 函数组件无法使用 ref 属性,因为他们没有实例。
Refs转发应用场景

解决获取子组件通内部的 DOM 元素/方法.

const FancyButton = React.forwardRef((props, ref) => {
    let myRef
    useImperativeHandle(ref, () => {
        return {
            func
        };
    })
    function func() {
        console.log('执行我', myRef);
    }
    return <button ref={ref => myRef = ref} className='FancyButton' > {props.children}</button >
})

function App() {
    let myHandle
    React.useEffect(() => {
        // useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。
        console.log(myHandle)
        console.log(myHandle.func())
    }, []) //模拟生命周期
    return (
        <FancyButton ref={handle => myHandle = handle} >Click me</FancyButton>
    )
}
使用props自定义onRef/onRefDom属性 用于获取子组件方法或属性

缺点:如果一个组件被多次使用,正常情况下想要调用其组件内的方法需要传入props来调用,每次传入的话就比较多余。


class Child extends React.Component {
    constructor(props) {
        super(props);
        this.props.onRef && this.props.onRef(this);
    }
    func() {
        console.log("执行我")
    }
    render() {
        return (<div ref={node => this.props.onRefDom(node)}>子组件</div>);
    }
}

class App extends React.Component {
    handleOnClick = () => {

    }
    componentDidMount() {
        console.log(this.Child)
        console.log(this.ChildDom)
        this.Child.func();
    }
    render() {
        return (<div>
            <button onClick={this.handleOnClick}>click</button>
            <Child onRef={node => this.Child = node} onRefDom={node => this.ChildDom = node}></Child>
        </div>);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值