几天前, 我们写了一篇关于即将到来的对我们的传统生命周期方法的变更的文章, 包括逐步迁移策略在 React 16.3.0 中, 我们添加了一些新的生命周期方法来帮助迁移我们还引入了新的 API, 用于长时间请求的特性: 一个官方的上下文 API 一个 ref 转发 API 和一个更语意化的 ref API
请继续阅读, 了解更多关于这个版本的信息
官方认证的 Context API
多年来, React 为 Context 提供了一个实验性的 API 虽然它是一个强大的工具, 但是由于 API 中固有的问题, 它的使用是不受欢迎的, 因此我们打算用一个更好的 API 来替代这实验性的 API
React 16.3 引入了一个新的 Context API, 它更高效, 同时支持静态类型检查和深度更新
注意
旧的 ContextAPI 将继续保留到 React 16.x, 所以您将有时间迁移
下面是一个示例, 说明如何使用新的上下文 API 注入主题:
- ##by 司徒正美 const ThemeContext = React.createContext('light');
- class ThemeProvider extends React.Component {
- state = {
- theme: 'light'
- };
- render() {
- return ( <ThemeContext.Provider value = {
- this.state.theme
- }> {
- this.props.children
- } </ThemeContext.Provider>
- );
- }
- }
- class ThemedButton extends React.Component {
- render() {
- return (
- <ThemeContext.Consumer>
- {theme => <Button theme={theme} />
- } </ThemeContext.Consumer>
- );
- }
- }/
- createRef API
以前, React 提供了两种管理 refs 的方法: 字符串 ref API 和回调 ref API 尽管字符串 ref API 比较方便, 但是它有几个缺点, 所以我们的官方推荐是使用回调 ref
React 16.3 为管理 refs 提供了一个新的方案, 它为字符串 ref 提供了方便, 并且没有任何缺点:
- ## by 司徒正美
- class MyComponent extends React.Component {
- constructor(props) {
- super(props);
- this.inputRef = React.createRef();
- }
- render() {
- return <input type="text" ref={this.inputRef} />;
- }
- componentDidMount() {
- this.inputRef.current.focus();
- }
- }
注意
除了新的 createRef API 外, 回调 refs 将继续得到支持
您不需要在组件中替换回调 refs 它们稍微灵活一些, 因此它们将继续作为一个高级特性
forwardRef API
高阶组件 (或 HOCs) 是在组件之间重用代码的常用方法基于上面的主题上下文示例, 我们可能会创建一个临时对象, 将当前的主题作为一个属性注入:
- ## by 司徒正美
- function withTheme(Component) {
- return function ThemedComponent(props) {
- return (
- <ThemeContext.Consumer>
- {theme => <Component {...props} theme={theme} />}
- </ThemeContext.Consumer>
- );
- };
- }
我们可以使用上述特殊的方式将组件连接到主题上下文, 而不必直接使用主题上下文例如:
- ## by 司徒正美
- class FancyButton extends React.Component {
- buttonRef = React.createRef();
- focus() {
- this.buttonRef.current.focus();
- }
- render() {
- const {label, theme, ...rest} = this.props;
- return (
- <button
- {...rest}
- className={`${theme}-button`}
- ref={this.buttonRef}>
- {label}
- </button>
- );
- }
- }
- const FancyThemedButton = withTheme(FancyButton);
- // We can render FancyThemedButton as if it were a FancyButton
- // It will automatically receive the current "theme",
- // And the HOC will pass through our other props.
- <FancyThemedButton
- label="Click me!"
- onClick={handleClick}
- />;
HOCs 通常会将 props 传递给它们包装的组件不幸的是, refs 没有冲透进去这意味着如果我们使用 FancyThemedButton, 我们就不能将 ref 添加到 FancyButton 中, 因此我们无法调用 focus()
新的代理 API 通过提供一种方法来拦截一个 ref, 并将其转发为一个普通的 props, 从而解决了这个问题:
- ## by 司徒正美
- function withTheme(Component) {
- // Note the second param "ref" provided by React.forwardRef.
- // We can attach this to Component directly.
- function ThemedComponent(props, ref) {
- return (
- <ThemeContext.Consumer>
- {theme => (
- <Component {...props} ref={ref} theme={theme} />
- )}
- </ThemeContext.Consumer>
- );
- }
- // These next lines are not necessary,
- // But they do give the component a better display name in DevTools,
- // e.g. "ForwardRef(withTheme(MyComponent))"
- const name = Component.displayName || Component.name;
- ThemedComponent.displayName = `withTheme(${name})`;
- // Tell React to pass the "ref" to ThemedComponent.
- return React.forwardRef(ThemedComponent);
- }
- const fancyButtonRef = React.createRef();
- // fancyButtonRef will now point to FancyButton
- <FancyThemedButton
- label="Click me!"
- onClick={handleClick}
- ref={fancyButtonRef}
- />;
组件生命周期钩子的变化
React 的类组件 API 已经存在多年, 几乎没有变化但是, 当我们为更高级的特性 (例如错误边界和即将到来的异步渲染模式) 添加支持时, 我们以它本来没有打算的方式来扩展这个模型
例如, 在当前的 API 中, 用一些非寻常的手段来阻止初始渲染是很容易的在某种程度上, 这是因为有太多的钩子来完成这项既定的任务, 而且还不清楚哪一个是最好的我们已经注意到错误处理的中断行为通常不会被考虑, 并且可能导致内存泄漏 (这也会影响即将到来的异步渲染模式) 当前的类组件 API 也使其他的工作变得复杂, 比如我们的代码优化器 (Prepack) 的工作
- componentWillMount,
- componentWillReceiveProps
, componentWillUpdate 这些钩子很容易引发问题, 并且也严重扰乱 React 的生命周期基于这些原因, 我们将废弃这些方法, 以支持更好的替代方案
我们认识到这一变化将影响许多现有的组件因此, 迁移路径将尽可能平缓, 并提供迁移方案(在 Facebook, 我们拥有 5 万多个 React 组件我们也依赖于一个渐进的发布周期!
注意
弃用警告将在 React16 以后的版本中启用, 一直保留到 17 发布时
即使在 React17 中, 仍然可以使用它们, 但是它们将添加 UNSAFE_前缀, 以表明它们可能导致问题我们还准备了一个自动化的脚本, 以便现有代码中重命名它们
除了废弃不安全的生命周期钩子外, 我们还增加了一些新的生命周期钩子:
getDerivedStateFromProps
用来 componentWillReceiveProps
getSnapshotBeforeUpdate
, 用在更新前从 DOM 中安全地读取属性
StrictMode 组件
<StrictMode />是一种专门用于暴露潜在问题的工具与 < Fragment />一样,<StrictMode/>将 不会渲染到视图中它能为其子组件激活额外的检查和警告
注意
<StrictMode />检查只在开发模式下运行; 它们不会影响生产构建
虽然严格的模式不可能捕获所有的问题(例如某些类型的窜改), 但它可以帮助很多人如果您在严格的模式下看到警告, 这些事情很可能会导致异步渲染的错误
在 16.3 版本中, StrictMode 帮助:
识别具有不安全生命周期钩子的组件
关于遗留字符串 ref API 用法的警告
检测意想不到的副作用
来源: https://segmentfault.com/a/1190000014083970