13.5ref的转发

在前面学习ref时说过,ref不能应用于函数式组件:

  • 因为函数式组件没有实例,所以不能获取到对应的组件对象

但是,在开发中我们可能想要获取函数式组件中某个元素的DOM,这个时候我们应该如何操作呢:

  • 注意能直接传入ref属性
  • 通过forwardRef高阶组件;
import React, { PureComponent, createRef, forwardRef } from 'react'

class Home extends PureComponent {
  render() {
    return (<h3>Home</h3>)
  }
}

// forwardRef 高阶组件,里面做了增强ref
const About = forwardRef(function About(props, ref) {
  return <h4 ref={ref}>About</h4>
})


export default class App extends PureComponent {
  constructor() {
    super();
    this.state = {
      HomeRef: createRef(),
      H3Ref: createRef(),
      AboutRef: createRef()
    }
  }
  render() {
    return (
      <div>
        <h3 ref={this.state.H3Ref}>app</h3>
        <Home ref={this.state.HomeRef} />
        <About ref={this.state.AboutRef} />
        <button onClick={e => this.printRef()}>打印ref</button>
      </div>
    )
  }
  printRef() {
    console.log(this.state.HomeRef.current);
    console.log(this.state.H3Ref.current);
    console.log(this.state.AboutRef.current);
  }
}

14.Portals的使用

某些情况下,我们希望渲染的内容独立于父组件,甚至是独立于当前挂载到的DOM元素中(默认都是挂载到id为root的DOM元素上的)。

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案:

  • 第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或 fragment;
  • 第二个参数(container)是一个 DOM 元素;

React组件化开发(6)- ref的转发&Portals&Portals&StrictMode(7)

通常来讲,当你从组件的 render 方法返回一个元素时,该元素将被挂载到 DOM 节点中离其最近的父节点

然而,有时候将子元素插入到 DOM 节点中的不同位置也是有好处的:

14.1Portals案例

我们准备开发一个Modal组件,它可以将它的子组件渲染到屏幕的中间位置

App.js

import React, { PureComponent, } from 'react'
import ReactDOM from "react-dom"

import "./portals.css"
class Modal extends PureComponent {
  render() {
    console.log(this.props.children[0]);
    console.log(this.props);
    return (
      ReactDOM.createPortal(
        this.props.children,
        document.getElementById("modal")
      )
    )
  }
}
export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Modal>
          <h1>TitleCenter</h1>
        </Modal>

      </div>
    )
  }
}

html 结构:

React组件化开发(6)- ref的转发&Portals&Portals&StrictMode(7)

样式:

React组件化开发(6)- ref的转发&Portals&Portals&StrictMode(7)

15.fragment

在之前的开发中,我们总是在一个组件中返回内容时包裹一个div元素:

React组件化开发(6)- ref的转发&Portals&Portals&StrictMode(7)

我们又希望可以不渲染这样一个div应该如何操作呢?

  • 使用Fragment
  • Fragment 允许你将子列表分组,而无需向 DOM 添加额外节点;

React还提供了Fragment的短语法:

  • 它看起来像空标签 <> </>;
  • 但是,如果我们需要在Fragment中添加key,那么就不能使用短语法
import React, { PureComponent } from 'react'

class Home extends PureComponent {
  render() {
    return (
      <React.Fragment>
        <h2>我-Fragment</h2>
        <ul>
          <li>你好</li>
          <li>你好</li>
          <li>你好</li>
        </ul>
      </React.Fragment>
    )
  }
}
class About extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      list: [{ name: "雷利", age: 40 }, { name: "罗杰", age: 42 }, { name: "御田", age: 39 }]
    }
  }
  render() {
    return (
      <div>
        {
          this.state.list.map((item, index) => {
            // return (
            // 使用了Fragment的短语法就能添加key
            // < key={item.name}>
            //   <div>{item.name}</div>
            //   <p>{item.age}</p>
            // </>
            // )
            return (
              <React.Fragment key={item.name}>
                <div>{item.name}</div>
                <p>{item.age}</p>
              </React.Fragment>
            )
          })
        }
      </div>
    )
  }
}

export default class App extends PureComponent {
  render() {
    return (
      <div>
        <Home />
        <About />
      </div>
    )
  }
}

16.StrictMode

StrictMode 是一个用来突出显示应用程序中潜在问题的工具

  • 与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。
  • 它为其后代元素触发额外的检查和警告。
  • 严格模式检查仅在开发模式下运行; 它们不会影响生产构建 。

你可以为应用程序的任何部分启用严格模式:

React组件化开发(6)- ref的转发&Portals&Portals&StrictMode(7)

  • 不会对Home启用严格模式检查
  • 对所有包裹在StrictMode里面的内容开启严格模式检查
16.1严格模式检测的是什么?

严格模式到底检查的是什么:

  1. 识别不安全的生命周期
  2. 使用过时的ref
  3. 使用废弃的findDOMNode方法的警告
  4. 检测意外的副作用

    • 这个组件的constructor会被调用两次;
    • 这是严格模式下故意进行的操作,让你来查看在这里写的一些逻辑代码被调用多次时,是否会产生一些副作用;
    • 在生产环境中,是不会被调用两次的;
  5. 检测过时的context API

    • 早期的Context是通过static属性声明Context对象属性,通过getChildContext返回Context对象等方式来使用Context的
文章目录