[译]迁移到新的 React Context Api
随着 React 16.3.0 的发布,context api 也有了很大的更新。我已经从旧版的 api 更新到了新版。这里就分享一下我(作者)的心得体会。
回顾
下面是一个展示如何使用旧版 api 的例子:
function Usage(props) {
return (
<Toggle onToggle={props.onToggle}>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<div>
<Toggle.Button />
</div>
</Toggle>
)
}
上面的代码会返回一个复合组件Toggle。这个组件可以让子组件共享隐式的状态。在某些简单的情况下可以用React.Children.map来处理。但是,这个例子需要使用 context api 来达到在 React 的某个组件树的任意节点分享 state 的目的。
旧的 Context Api
这是一个旧版 context api 的应用例子:
const TOGGLE_CONTEXT = "__toggle__";
// Toggle on
function ToggleOn({ children }, context) {
const { on } = context[TOGGLE_CONTEXT];
return on ? children : null;
}
ToggleOn.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired
};
// Toggle off
function ToggleOff({ children }, context) {
const { on } = context[TOGGLE_CONTEXT];
return on ? null : children;
}
ToggleOff.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired
};
// Toggle button
function ToggleButton(props, context) {
const { on, toggle } = context[TOGGLE_CONTEXT];
return <Switch on={on} onClick={toggle} {...props} />;
}
ToggleButton.contextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired
};
// Toggle
class Toggle extends React.Component {
static On = ToggleOn;
static Off = ToggleOff;
static Button = ToggleButton;
static defaultProps = { onToggle: () => {} };
static childContextTypes = {
[TOGGLE_CONTEXT]: PropTypes.object.isRequired
};
state = { on: false };
toggle = () =>
this.setState(
({ on }) => ({ on: !on }),
() => this.props.onToggle(this.state.on)
);
getChildContext() {
return {
[TOGGLE_CONTEXT]: {
on: this.state.on,
toggle: this.toggle,
}
};
}
render(){
return <div>{this.props.children</div>
}
}
在就的 API 里,你必须用一个字符串指定要分享的 state。然后通过getChildContext方法返回实际的 context。在父组件里通过childContextTypes来指定发出的 context 的类型,在子组件里用contextTypes来指定接收的 context 的类型。我(作者, 下文同)从来不喜欢这样不直接的方式, 平时也尽量不这么做。另外,还要使用静态属性,才能保证 context 值传入子组件。 我也不喜欢这样。
另一个问题是如果shouldComponentUpdate方法返回 false 的话,context 的值是不会变的。当然这也有变通的方法,具体可以参考这个repo。
新的 Context API
新的 context api 没有这些问题,这也是我为什么这么激动的原因。上面的例子可以更新为:
const ToggleContext = React.createContext({
on:false,
toggle: () => {},
});
class Toggle extends React.Component {
static On = ({children}) => (
<ToggleContext.Consumer>
{({on})=>(on ? children: null)}
</ToggleContet.Consumer>
)
static Off = ({children}) => (
<ToggleContext.Consumer>
{({on}) => (on ? null : children)}
</ToggleContext.Consumer>
);
static Button = props => (
<ToggleContext.Consumer>
{({on, toggle}) => (
<Switch on={on} toggle={toggle} {...props} />
)}
</ToggleContext.Consumer>
)
toggle = () => this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on)
);
state = {on: false, toggle: this.toggle};
render() {
return (
<ToggleContext.Provider value={}>
{this.props.children}
</ToggleContext.Provider>
);
}
}
旧的API的问题都没有了。现在不仅没有了不直接的字符串,还有了明显的组件:Provider和Consumer分别提供和消费context。
每一个子组件都需要用consumer子组件,就想在就api里需要有静态属性一样)。但是,两个api的这个问题都可以通过基于render props的高阶组件来解决。非常简单!
另一个通过shouldComponentUpdate返回false来更新的问题也解决了。新的context api会自动处理这个问题。
最后一个非常好的改变是子组件都使用了render props模式。这样在新的context api里也可以对外界暴露非常优雅的接口。
新api的问题
这就是在新的api里通过Provider的value属性给子组件消费的值,只有在你想要子组件重绘的时候才会改变。
这也就是说在render方法里使用`value={{on: this.state.on, toggle: this.toggle}}是不被推荐的。
这是因为没次render都会传入一个新的对象,即使state本身没有改变。因为是一个新的对象,那么所有的子组件也都会重绘。
这个影响在实际使用的时候会很大。一般来说最好是传入一个只有在state改变时才改变的值。也就是为什么说value={this.state}。
如果你不想传入整个state给消费者,那么你可以使用这个Ryan Florence的这个小技巧。
只不过这也还是会有一个小问题,我需要把toggle方法存入state里。这也显得很奇怪,不过这只是一个小瑕疵,不影响大局。
总结
新的context api绝对是React团队带来的一个非常好的改变。希望你也能和我一样的喜欢。
另外:如果你还不能用16.3.0这个版本,那么你可以添加一个polyfill来使用新的api。这个polyfill是create-react-context。
from:https://blog.kentcdodds.com/migrating-to-reacts-new-context-api-b15dc7a31ea0
[译]迁移到新的 React Context Api的更多相关文章
- [React] Use the new React Context API
The React documentation has been warning us for a long time now that context shouldn't be used and t ...
- React Context API
使用React 开发程序的时候,组件中的数据共享是通过数据提升,变成父组件中的属性,然后再把属性向下传递给子组件来实现的.但当程序越来越复杂,需要共享的数据也越来越多,最后可能就把共享数据直接提升到最 ...
- 10分钟学会React Context API
Create-react-app来学习这个功能: 注意下面代码红色的即可,非常简单. 在小项目里Context API完全可以替换掉react-redux. 修改app.js import React ...
- React 16.3来了:带着全新的Context API
文章概览 React在版本16.3-alpha里引入了新的Context API,社区一片期待之声.我们先通过简单的例子,看下新的Context API长啥样,然后再简单探讨下新的API的意义. 文中 ...
- React 新 Context API 在前端状态管理的实践
本文转载至:今日头条技术博客 众所周知,React的单向数据流模式导致状态只能一级一级的由父组件传递到子组件,在大中型应用中较为繁琐不好管理,通常我们需要使用Redux来帮助我们进行管理,然而随着Re ...
- React 全新的 Context API
Context API 可以说是 React 中最有趣的一个特性了.一方面很多流行的框架(例如react-redux.mobx-react.react-router等)都在使用它:另一方面官方文档中却 ...
- 手写一个React-Redux,玩转React的Context API
上一篇文章我们手写了一个Redux,但是单纯的Redux只是一个状态机,是没有UI呈现的,所以一般我们使用的时候都会配合一个UI库,比如在React中使用Redux就会用到React-Redux这个库 ...
- 简单整理React的Context API
之前做项目时经常会遇到某个组件需要传递方法或者数据到其内部的某个子组件,中间跨越了甚至三四层组件,必须层层传递,一不小心哪层组件忘记传递下去了就不行.然而我们的项目其实并没有那么复杂,所以也没有使用r ...
- React Hooks & Context API
React Hooks & Context API responsive website https://reactjs.org/docs/hooks-reference.html https ...
随机推荐
- Unity UGUI 小知识
1.有个控件叫Selectable 这个控件在button,slider等身上有,也可以自行添加,可通过API搜索所有带这个控件的物体统一控制. 2.实现ScrollView只使用Scrollbar操 ...
- RabbitMQ消费者抛异常日志持续打印的问题
场景 消费者接受消息,进行一系列处理,但是由于某些原因处理过程中该消费者的抛出了异常,并且不捕获(直接 throws IOException 抛出去): 由于抛出了IOException,那么这条消息 ...
- html 分页
/*列表分页底部按钮*/ div.tablefooter{ color: #4f6d95; } select.pageLength{ border: 1px solid #d0daea; border ...
- win7安装oracle 10g问题总结。
1.安装oracle10g的时候,出现此问题,如图: 右键安装程序(setup.exe) -> 属性 -> 兼容性 -> 以兼容模式运行这个程序 windows xp( servi ...
- 统一集中管理系统cronsun简介,替代crontab
一.背景 crontab 是 Linux 系统里面最简单易用的定时任务管理工具,相信绝大多数开发和运维都用到过.在咱们公司,很多业务系统的定时任务都是通过 crontab 来定义的,时间长了后会发现存 ...
- json转换对象中出现null属性的解决方法
前言:当数据进行json转换时,当属性值为null时,json解析就会中断,导致接下来的数据无法正确获取.原则上来讲服务器端发送的json字符串不允许存在属性值为空的情况,但是如果服务器端发送了nul ...
- CAPTCHA--验证码
验证码开发有两种方法: 1.自己用代码画一个 2.调用ValidateCode.jar工具包 第一种方式: 创建一个动态web工程 编写一个Servlet,在该Servlet内进行如下操作 验证码开发 ...
- ServletConfig、ServletContext 的应用
一.ServletConfig对象及其应用(用的不多) 1. Context和ContextPath:一个web工程,若名为JavaWeb,访问的路径为:http://localhost:8080/J ...
- P2880 [USACO07JAN]平衡的阵容Balanced Lineup(RMQ的倍增模板)
题面:P2880 [USACO07JAN]平衡的阵容Balanced Lineup RMQ问题:给定一个长度为N的区间,M个询问,每次询问Li到Ri这段区间元素的最大值/最小值. RMQ的高级写法一般 ...
- yarn 常用命令
1.安装 yarn npm install yarn -g 2.卸载yarn npm uninstall yarn -g