作者 Brian Vaughn 2018年3月29日
几天前, 我们 写了一篇关于对以前的生命周期方法进行更改的文章, 包括逐步迁移策略。 在React 16.3.0中, 我们正在添加一些新的生命周期方法来辅助迁移。我们还为长期被要求的功能引入了新的API: 一个官方的context API,一个转发的ref API和一个更符合人类使用的ref API.
官方 Context API
多年来,React仅提供了一个实验性的context API。尽管它是一个非常强大的API,但是,因为它固有问题以及我们打算用一个更好的API来替换这个实验的API,所以这个API一般不被推荐使用。
版本16.3引入了一个新的context API,它非常高效并且支持静态类型检查和深度更新。
注意
旧的context API将继续适用于所有React 1.6x版本,所以你将有足够的时间进行迁移。
下面是一个例子,说明如何使用新的context API注入一个『theme』:
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的方法:传统的字符串形式API和回调函数API。尽管字符串引用API是两者中使用最方便的,但它也有几个缺点 ,所有我们官方的建议是使用回调函数形式代替它。
版本16.3增加了一个管理refs的新的选项,它提供了使用字符串形式ref的便利性而且没有任务缺点:
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,Callback refs 将会继续得到支持。你没有必要替换掉你组件中的callback refs。它们稍微的更灵活一点,所以它们仍然是一个比较先进的功能。
forwardRef
API
高阶组件 (or HOCs) 是在组件间复用的代码的常用方法。基于上面的主题背景示例,我们中以创建一个HOC,它以属性的方式将当前『theme』进行注入:
function withTheme(Component) {
return function ThemedComponent(props) {
return (
`<ThemeContext.Consumer>`
{theme => `<Component {...props} theme={theme} />`}
`</ThemeContext.Consumer>`
);
};
}
我们可以使用上面的HOC将组件直接连接到主体上下文,而无需直接使用 ThemeContext
。例如:
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);
// 我们可以渲染FancyThemedButton,就好像它是一个FancyButton
// 它将会自动接收当前『theme』,
// 同时HOC也会传递我们其它的props。
`<FancyThemedButton
label="Click me!"
onClick={handleClick}
/>`;
HOCs通常将会把props传递给它们包裹着的组件。不幸的是, refs不会被传递。这意味着,如果我们使用FancyThemedButton
,我们将无法通过ref和FancyButton
进行连接,所以我们无法调用focus()
。
新的forwardRef
API解决了这个问题,它提供了一个方法来拦截ref
,并将它作为了普通的prop进行传递:
function withTheme(Component) {
function ThemedComponent({forwardedRef, ...rest}) {
return (
`<ThemeContext.Consumer>`
{theme => (
// Assign the custom prop "forwardedRef" as a ref
`<Component
{...rest}
ref={forwardedRef}
theme={theme}
/>`
)}
`</ThemeContext.Consumer>`
);
}
// 注意第二个参数"ref"是由React.forwardRef提供的。
// 我们可以将它作为变通的props传递给ThemedComponent,例如 "forwardedRef"
// 然后它可以被连接到这个组件。
return React.forwardRef((props, ref) => (
`<ThemedComponent {...props} forwardedRef={ref} />`
));
}
// 在这里,我们假设FancyButton已经被导入到当前上下文
const FancyThemedButton = withTheme(FancyButton);
// 通过Referenace API创建一个ref,
const fancyButtonRef = React.createRef();
// fancyButtonRef 现在指向 FancyButton
`<FancyThemedButton
label="Click me!"
onClick={handleClick}
ref={fancyButtonRef}
/>`;
组件生命周期变更
React类组件的API已经有好多年了,而且几乎没有变化。但是,当我们添加对更高级功能的支持时(比如错误边界和即将到来的异步渲染模式),我们会以不是我们想要的方式来扩展此模型。
例如,使用当前的API,可以很容易的阻止非必要的逻辑进行初始渲染。部分原因是因为完成某项任务的方式太多,而且哪一个最好也不清楚。我们已经观察到错误中断的处理行通常不被考虑在内,并且可能导致内存泄漏(它会影响到即将到来的异步渲染模式)。目前的类组件API也使其他工作复杂化,就像我们在原型化React编译器方面的工作一样。
这些问题在组件生命周期(componentWillMount
, componentWillReceiveProps
, and componentWillUpdate
)的一个子集中更加的恶化。这些也恰好是造成React社区最混乱的生命周期问题。出于这些原因的考虑,我们将会降低这些方法的使用,转而使用更好的方法代替。
我们意识到这些变更将会影响到现有的组件。因此,迁移路径将会是渐进式的,并且会提供补救措施。(在Facebook上,我们维护了超过50,000个React组件。 我们也依赖于一个渐进的发布周期! )
注意:
弃用警告将在未来的16.x版本中启用,但旧版生命周期将继续运行至17.x版。
即使在17.x版中,仍然可以使用它们,但它们会以『UNSAFE_』为前缀被重命名,以表明它们可能会引起问题。我们还准备了一个自动化的脚本来在现有代码中对它们重新命名。
除了摒弃不安全的生命周期外,我们还增加了一些新的生命周期:
getDerivedStateFromProps
是一个比较安全的方法来替代以前componentWillReceiveProps
.getSnapshotBeforeUpdate
用于更安全的读取属性,比如在更新之前获取DOM。
StrictMode
Component
StrictMode
是一个突出显示应用潜在问题的工具。像Fragment一样,StrictMode不会呈现任何可见的UI。它会为子组件作额外的检查并发出警告。
注意:
StrictMode
检查仅仅运行在开发模式下; 它们不影响生产构建。
尽管在严格模式下不可能捕获所有的问题(例如:某些类型的突变),但在它在大多数情况下还是很有用的。如果你在严格模式下看到警告,这些东西可能会引起异步渲染的错误。
在16.3版中,StrictMode
提供以下帮助:
- 识别不安全的生命周期组件
- 对使用字符串ref API进行警告
- 检测潜在副作用
随着未来React的发版,将会添加更多的功能。
编辑此页面