react new context API的一次实践(补充)
这是一篇我发在掘金上的文章,原文有一个我没有解决的问题,在网友的解答下我找到了答案,我把文章重新修改编辑后,同步发送到这里,希望能对大家有所帮助。 最近接到一个简单的内部项目,逻辑并不复杂,就想着不用redux了,用react的new context API试试看,折腾了两天,把过程和感想跟大家分享下。 由于是公司的项目,所以下文的示例代码都是我重新写的,望见谅! 基本用法首先,让我们来看一下这个接口的基本用法: import React,{ createContext } from "react"; const Context = createContext({ gender: "male" });; Context实例提供两个组件:Provider和Consumer const ContextProvider = Context.Provider; const ContextConsumer = Context.Consumer; 其中ContextProvider是数据的发布方,而ContextConsumer是数据的订阅方。 <ContextProvider value={{ name: "A",age: 18 }}> <ContextConsumer> { context => ( <div> name: <span>{context.name}</span> age: <span>{context.age}</span> </div> ) } </ContextConsumer> </ContextProvider> ContextProvider作为数据的发布方,它拥有一个名为value的属性,用于维护数据内容,通过value传递给ContextProvider的数据会被发布出去。 关于调用createContext方法时候的传参,理论上第一个传参应该是初始化的数据,但是我使用后发现,如果在ContextProvider的value属性中不传入对应的属性的话,无法在ContextConsumer中获取到那个初始化的属性。 const Context = createContext({ gender: "male" }); <Context.Provider value={{ name: "A",age: 18 }}> <Context.Consumer> { context => ( <div> name: <span>{context.name}</span> age: <span>{context.age}</span> </div> ) } </Context.Consumer> </Context.Provider> 这个例子中,我始终无法获取到gender的值。 补充经过网友的解答和我自己的试验,这个问题得到了解答:
实践为了适应项目的需求,我主要是对ContextProvider和ContextConsumer做了封装。 ContextProvider由于在我的项目中组件需要订阅并且修改和维护被发布的数据,所以我需要有一个可以维护这些数据的地方。因此我创建了一个名为MyProvider的高阶组件,并把它放在组件树的顶层,而各个组件需要订阅的数据就存放在MyProvider的state中,那么我只需要维护它的state就能维护这些全局的数据了。 export class MyProvider extends React.Component { constructor() { super(); this.state = { name: "A",age: 18 }; this.updateContext = this.updateContext.bind(this); } updateContext(newData) { this.setState(Object.assign({},this.state,newData)); } render() { const contextData = { data: this.state }; Object.defineProperty(contextData,"updateContext",{ value: this.updateContext }); return ( <Context.Provider value={contextData}> {this.props.children} </Context.Provider> ); } } MyProvider组件返回的是ContextProvider组件,并把MyProvider的state作为要发布的数据绑定到了ContextProvider的value属性上。 ContextConsumer考虑到ContextConsumer作为订阅方使用比较频繁,为了方便其他组件的使用,我将它封装到高阶组件中,并作为函数的返回值使用,如下: export const MyConsumer = Component => { return props => ( <Context.Consumer> {context => { return <Component context={context} {...props} />; }} </Context.Consumer> ); }; MyConsumer函数返回一个高阶组件。在这个高阶组件中,我把ContextConsumer提供的数据加入到Component的props中,这样我只需要在export组件的时候调用MyConsumer,并且在组件中使用 class MyComponent extends React.Component { addAge() { const { data: { age },updateContext } = this.props.context; const newAge = age + 1; updateContext({ age: newAge }); } render() { const { name,age } = this.props.context.data; return ( <div> name: <span>{name}</span> age: <span>{age}</span> <button onClick={() => this.addAge()}>add age</button> </div> ); } } export default Consumer(MyComponent); 在这个例子中,点击按钮,调用this.props.context.updateContext方法就可以通过更新MyProvider的state来修改被发布数据中的age的值。 示例代码:react-new-context-api-demo 小结我折腾了两天之后才反应过来,这不就是一个类似于redux的东西吗?可能由于我redux用的多了,对于Prvider和Consumer的封装下意识的做成了类似redux的用法。再加上使用MyProvider的state作为唯一数据源,又有updateContext这个有点像dispatch的方法来更新数据,乍一看之下,还是有点redux的影子的。当然了,我自己写的完全没有redux那么好用,也没有reudx那么严谨。所以,后来我又花了一个上午的时间改用了redux。但是通过这次的实践,也算是熟悉的new context api的用法,对redux也加深了了解吧。最后,如果你只是想要订阅数据,new context api是个不错的选择;但是如果你想要修改和维护被发布的数据,使用redux会更方便和安全。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |