context api总是很让人迷惑。这个api是官方的,但是官方又不希望开发者们使用这个api,说是这个api会在以后发生改变。现在就是那个改变的时刻。新的api已经被merge了。而且它看起来更加的“用户友好”了。尤其是你不得不使用redux、mobx的时候,可以选择新的context api实现更加简单的状态管理。
新的api用起来非常的简单:react.createcontext(),这样就创建了两个组件:
import {createcontext} from 'react';
const themecontext = createcontext({
background: 'yellow',
color: 'white'
});
调用createcontext方法会返回两个对象,一个是provider,一个是consumer。
那个provider是一个特殊的组件。它可以用来给子树里的组件提供数据。一个例子:
class application extends react.component {
render() {
<themecontext.provider value={{background: 'black', color: 'white'}}>
<header />
<main />
<footer />
</themecontext.provider>
}
}
上例展示了如何传递“theme” context的。当然这些值可以是动态的(比如,基于this.state)。
下一步就是使用consumer。
const header = () => {
<themecontext.consumer>
{(context) => {
return (
<p style={{background: context.background, color: context.color}}>
welcome!
</p>
);
}}
</themecontext.consumer>
}
如果在render consumer的时候没有嵌套在一个provider里面。那么就会使用createcontext方法调用的时候设置的默认值。
注意:
consumer必须可以访问到同一个context组件。如果你要创建一个新的context,用的是同样的入参,那么这个新建的context的数据是不可访问的。因此,可以把context当做一个组件,它可以创建一次,然后可以export,可以import。
这个新的语法用了function as child模式(有时也叫做render prop模式)。如果不是很熟悉这个模式,那么推荐你看一下这些文章。
新的api不再要求你声明contextprops了。
context传递的数据和context.provider组件的value属性是一样的。对provider数据的修改会引起所有的消费者(consumer)重绘。
新的声明周期方法参考这个rfc。新的声明周期方法会被引入,而旧的会被废弃。
这一改变主要是为了强制推行最佳实践。你可以看看这篇文章来了解一下为什么这些生命周期方法会变得很诡异。这些最佳模式在react 16的异步绘制模式(async mode)下显得非常重要。
要被废弃的方法:
componentwillmount--使用componentdidmount代替
componentwillupdate--使用componentdidupdate代替
componentwillreceiveprops--使用一个新的方法:static getderivedstatefromprops来代替。
不过这些并不会立刻发生,他们可以用到react 16.4。在react 17里将被彻底移除。如果你开启了strictmode或者asyncmode,可以通过这样的方式来使用,但是会收到警告:
unsafe_componentwillmount
unsafe_componentwillreceiveprops
unsafe_componentwillupdate
static getderivedstatefromprops当componentwillreceiveprops我们需要其他的方式根据props的变动更新state。社区决定引入一个新的static方法来处理这个问题。
什么是静态方法?一个静态方法就是存在于类内,而不是类的实例内的方法。静态方法访问不到this,并且在声明的时候有static关键字在前面修饰。
但是,问题来了。既然这个方法没有办法访问this,那么如何调用this.setstate呢?答案就是,不调用。这个方法直接返回需要更新的state的数据,或者返回null,如果没有什么需要更新的话。
static getderivedstatefromprops(nextprops, prevstate) {
if(nextprops.currentrow === prevstate.lastrow) {
return null;
}
return {
lastrow: nextprops.currentrow,
iscrollingdown: nextprops.curentrow > prevstate.lastrow
}
}
调用这个方法和之前调用this.setstate的效果是一样的。只会修改这些返回的值,如果是null的话则不修改state。state的其他值都会保留。
值得注意的事你需要定义初始state的值。无论是在constructor里,或者是类属性。否则会报警告。
这个方法getderivedstatefromprops()会在第一次挂载和重绘的时候都会调用到,因此你基本不用在constructor里根据传入的props来setstate。
如果定义了getderivedstatefromprops后,又定义了componentwillreceiveprops。那么,只有前者会被调用,并且你会收到一个警告。
一般你会使用一个回调来保证某些代码实在state更新之后才被调用的。那么,请把这些代码都移到componentdidupdate里。
如果你不喜欢使用static关键字,那么你可以这样:
componentname.getderivedstatefromprops = (nextprops, prevstate) => {
// your code here
}
static mode严格模式是一个新的方式来确保你的代码是按照最佳实践开发的。它实际是一个在react.strictmode下的组件。它可以用在你的组件树的任何一部分上。
import {strictmode} from 'react'
class application extends react.component {
render() {
return (
<strictmode>
<context.provider value={{background: 'black', color: 'white'}}>
<header />
<main />
<footer />
</context.provider>
</strictmode>
);
}
}
如果一个在stricmode子树里的组件使用了componentwillmount方法,那么你会看到一个报错消息。
asyncmode异步模式在react.unsafe_asyncmode下。使用asncmode也会打开strictmode模式下的警告。
相关推荐:
react 16.3之context api详解
以上就是react 16.3新特性分析的详细内容。