推荐文章 | 简介 | 链接 |
---|---|---|
🌍从 MVC 到微服务:架构演化的历程与应用场景(含代码演示) | 这篇文章是技术深度文章,作者详细阐述了从MVC架构到微服务架构的演化过程,并结合具体的代码示例,展示了不同架构的设计思想和实现逻辑。 |
🐤本篇文章是『从零玩转 TypeScript + React 项目实战』系列文章的第 7 篇,主要介绍『Dva』中的订阅
经上一篇『Dva』订阅,文章介绍,了解了下 Model 当中的 Subscription 也就是所谓的订阅,到此我们也掌握了如何通过 Dva 来管理数据。
那么本篇文章呢,我就来继续介绍下在 dva 中如何使用路由。
在 dva 中如何使用路由呢?要想使用路由,要想看到路由的效果的话,首先,是不是要先多搞几个组建,对吧?
所以我就不管三七二十一,我在定义一个 about 组件,再定义一个 aboutModel 保存一下 about 组件的数据,然后呢代码如下,先是定义 aboutModel,aboutModel 的命名空间呢叫 about,aboutModel 保存了一个 count,aboutModel 有自己的 Reducers,aboutModel 自己的 Reducers 有两个方法可以对 count 进行增加和减少的操作。
这个 aboutModel 内容大致就这些,代码如下:
let aboutModel = {
namespace: 'about',
state: {
count: 123
},
reducers: {
add: (state, action) => {
return {
count: state.count + action.count
}
},
sub: (state, action) => {
return {
count: state.count - action.count
}
}
}
}
定义好 aboutModel 之后呢,是不是还要告诉 dva,我需要使用这个 aboutModel:
app.model(aboutModel);
告诉 dva 要使用 aboutModel,我是不是还要将 aboutModel 当中的数据和方法映射到 about 组件中去,这个时候呢,我直接将 home 组件的内容拷贝一份改吧改吧。
About:
function About(props) {
return (
<div>
<p>{props.count}</p>
<button onClick={() => {
props.increment()
}}>+
</button>
<button onClick={() => {
props.decrement()
}}>-
</button>
</div>
)
}
About 组件呢,分别做了展示和方法调用的操作,从映射的数据当中拿到映射的 count 进行了展示,在分别调用了映射的 increment
和 decrement
方法。
接下来是不是就要来映射一下,通过 saga 的 connect 方法来映射,映射之前我还需要处理一下映射,编写 mapStateToProps 方法来映射,这次我要映射的数据名称为 count,这个 count 从哪来,是不是从命名空间为 about 的这个 Model 中获取。
为了防止 mapStateToProps 与 home 的 mapStateToProps 名称重复我这里定义为叫 mapStateToPropsAbout
:
const mapStateToPropsAbout = (state) => {
return {
// 需要从传入的 state 的命名空间中拿到对应 Model 保存的数据
count: state.about.count,
}
};
数据映射完成之后,再来看派发任务,一样的拷贝一下之前的 mapDispatchToProps,之前编写的 mapDispatchToProps 是针对于 home 的,但这次是给 about 进行映射,所以也是一样为了防止 mapDispatchToProps 与 home 的 mapDispatchToProps 名称重复我这里定义为叫 mapDispatchToPropsAbout
:
不过目前都是派发到 home 当中,现在是不是要派发到 about,所以更改一下,并且告诉它我要修改的是 count,为了区分 home 与 about 的增加与减少呢,这里我给它设置的传参为 2:
const mapDispatchToPropsAbout = (dispatch) => {
return {
increment() {
dispatch({type: 'about/add', count: 2});
},
decrement() {
dispatch({type: 'about/sub', count: 2});
}
}
};
mapStateToPropsAbout,mapDispatchToPropsAbout 都处理编写好了之后,是不是基本大概差不多就搞定了,最后再通过 connect 连接到 about 组件上去,这样就完成了一次 about 组件的映射。
const AdvAbout = connect(mapStateToPropsAbout, mapDispatchToPropsAbout)(About);
接下来就可以在 app 中使用 about 了,来到 app 组件代码中使用 about,为了能看出效果我弄了一个 hr 标签,分割一下:
运行项目,浏览器查看:
将之前的异步数据处理的代码可以先注释掉或者可以删掉,本次就关注 home 与 about 的内容,Home 组件就只留如下图代码即可:
home 的 +、- 增值是 1,about 是 2:
有了多个组件,就可以利用本次文章要介绍的路由来切换组件了,利用路由切换组件怎么切换呢,也非常的简单,在 dva 中它对路由进行了一个简单的封装。
要想使用它就得要先导入 dva 封装好的路由,从哪导入呢,从 dva 的 router 当中导入,我这里采用解构的方式解构出想要的内容,在 dva router 中,它给我们封装好了一个 Router 与 Route:
import { Router, Route } from 'dva/router'
接下来就可以使用了,找到 app,我先将 app 过去的代码全部干掉,或者可以进行注释,那么就注释掉吧,保留下,还是还是删除掉吧,反正我进行了项目 Git 管理,就不会有这样的问题了。然后我在 app 中首先放上一个 Router:
function App() {
return (
<Router>
</Router>
);
}
因为 Router 里面呢只能有一个根,所以我就在 Router 中放上一个 Fragment(对 Fragment 不清楚的请查看:https://zh-hans.react.dev/reference/react/Fragment),放完 Fragment 之后我然后再 Fragment 中放上一个 Route:
function App() {
return (
<Router>
<>
<Route></Route>
</>
</Router>
);
}
在 Route 中可以通过 path 可以告诉它匹配哪一个地址,我这里就将这个 Route path 设置为 home,然后呢在 Route 中还有一个 component,这个 component 意思是如果是 home 就要渲染哪一个组件,我这里渲染 AdvHome:
About 也是同理可证:
<Route path={'/home'} component={AdvHome}/>
<Route path={'/about'} component={AdvAbout}/>
好,基本上代码写完了,回到网页当中刷新一下,不出意外的话应该是会报错:
为什么会报错呢?如果说回顾一下过去在使用 React Router 的时候是不是区分模式,那么区分什么模式呢,是不是区分 history 和 hash 模式,但现在我使用的是 dva 给我们封装好的 Router 的时候,是不是并没有告诉 Router 是什么模式的。
怎么告诉 Router 是什么模式,这个时候就需要从创建 dva 实例这行代码说了,这里也是本次要说的注意点。
那么如上这些我是怎么知道的呢?非常的简单,回到 dva 的官方文档,找到 API,然后找到创建 dva 实例的文档说明:https://dvajs.xiniushu.com/api/#app-dva-opts
经过观察,dva(opts),是不是说明了接收一个参数名为 opts 的内容,opts 是什么是不是一个对象:
可以通过该对象的 history 修改模式,官方也为 history 做了说明,history:指定给路由用的 history,默认是 hashHistory
,经过这样的解释之后是不是就验证了我的说法。
好,验证了我的说法之后还没完,既然它默认是 hash,那为什么它还会报错呢?原因很简单,默认是 hash 但是我没有告诉 Router 就要使用 hash 模式,那怎么告诉 Router 就要使用 hash 模式呢?
也很简单,继续看官方文档找到 app.router
的方法文档,也就是 dva 的 router 文档:
过去我们是不是在代码中通过 router 将来我要渲染哪个组件,如下这段代码:
其实在告诉 dva router 渲染哪个组件的时候,还可以做一件事情,这个时候回到文档,发现它代码中通过解构的方式解构出来了一个 history,说明什么,说明在渲染的时候会给这个函数传参:
所以说,我代码也可以通过这种方式解构出来 history,也就是当前的模式:
再通过如上我所说的,如果没有指定那么就是默认为 hash 模式,如果指定了这个解构出来的就是你指定的那个模式,总结说一下就是,dva 的 router 方法在执行回调函数的时候会传递一个对象给我们,我们可以从这个对象中解构出当前理由模式。
如果在创建 dva 实例的时候,没有指定模式,那么得到的就是 hash 模式,如果在创建 dva 实例的时候指定了模式,那么得到的就是我们指定的模式。
我代码中通过 dva 创建的时候是不是没有指定模式,那么 app.router(({history}) => <App/>);
这里的 history 就是 hash,拿到了当前的模式之后呢,我是不是可以直接将该模式传递给我的 app 组件:
app.router(({history}) => <App history={history}/>);
在 app 组件当中通过 props 接收一下,接收到了之后再通过 Router 中的 history 属性告诉 Router 是什么模式:
function App(props) {
return (
<Router history={props.history}>
<>
<Route path={'/home'} component={AdvHome}/>
<Route path={'/about'} component={AdvAbout}/>
</>
</Router>
);
}
现在使用的是 hash 模式,前说过了,这些内容我都是怎么知道的我都是从文档里面抄的,官方文档也是解构当前的模式,然后将模式告诉 Router:
回到网页刷新一下,就不会报错了,路径地址后面有一个 #
号,是不是意味着当前是 hash 模式,如果我在当前的地址后面输入 home 是不是应该切换到 home:
访问 about 是同理可证的,不测试了,那么这个使用我不想使用 hash 了,该怎么办?
我想使用 history,这个时候怎么做呢?是不是还是回到官方文档当中找到创建 dva 实例对象的代码,已经告诉我们如何操作了,首先得要导入 createHistory 这个方法:
import createHistory from 'history/createBrowserHistory';
然后再代码中创建 dva 实例的时候传递一个对象,通过对象的 history 属性来告诉 dva Router 使用什么路由模式,告诉它我修改路由模式为我指定的:
const app = dva({
history: createHistory()
});
如上代码的意思就是我修改了 dva 的理由模式,修改为了 history 模式,修改完之后,我利用 hash 的方式访问,会发现页面访问不出来了:
为什么呢?是不是因为路径地址中有 #
号,就是因为我修改了 dva 的路由模式,history 模式是没有 #
号的,把 #
号去掉直接输入 home:
访问 about 同理可证的,不测试了,好了如上内容就是在 dva 中如何使用路由,以及呢如何指定路由模式。
通过本文的学习,您可以掌握以下知识点:
connect
将 Model 的状态和方法映射到组件中,实现组件数据的动态更新。Router
和 Route
实现不同路径对应不同组件的渲染。通过 path
属性指定路由路径,component
属性指定渲染组件。hash
和 history
。在创建 Dva 实例时,可以通过 history
属性指定路由模式。app.router
和 Router
的 history
属性,实现一致性。🐤如果您觉得本文对您有所帮助,欢迎点赞、收藏或分享,您的支持是我创作的最大动力!
这篇文章的内容就介绍到这里,期待我们下次的相遇。感谢您花时间阅读,如果有任何问题或想法,欢迎在评论区留言。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。