打造开箱即用的 react 移动端框架(二)
先前那篇文章已经讲了有关 React 移动的配置,接下来讲讲 dva 和 react-keeper 如何配置到移动端框架
该脚手架基于 create react app
创建,方便快速搭建 react 移动端项目
上篇文章地址:# 打造开箱即用的 react 移动端框架
gitHub: react-mobile
在线地址:react-mobile-Domesy
配置dva
首先,我们只需要 dva-core dva-loading
和react-redux
配合使用即可
执行命令:
yarn add react-redux yarn add dva-core dva-loading 复制代码
创建 dva.js
这里只说一下大体思路,我们需要创建两个方法,一个是 createApp, 一个是 getDispatch
createApp 的作用就是将 数据注入到 model,然后设置 store
getDispath 的作用就是,将 dispatch 导出,让其有操作的方法
我们直接上代码:
import { create } from 'dva-core' import createLoading from 'dva-loading' let app let store let dispatch let registered function createApp(opt) { opt.onAction = [] app = create(opt) app.use(createLoading({})) // 注入model if (!registered) { opt.models.forEach((model) => app.model(model)) } registered = true app.start() // 设置store store = app._store app.getStore = () => store app.use({ onError(err) { console.log(err) }, }) // 设置dispatch dispatch = store.dispatch app.dispatch = dispatch return app } export default { createApp, getDispatch() { return app.dispatch }, } 复制代码
创建models
之后我们单独在src
下单独创建 model
然后将其导出就ok了
import app from './app' export default [ app, ] 复制代码
集中配置
在之后,我们只需要在 App.tsx
中使用react-redux
的Provider
引用下就完成了
import React from 'react'; import { Provider } from 'react-redux' import models from './models' import dva from './utils/dva' const app = dva.createApp({ models, }) const store = app.getStore() const App: React.FC = () => { return ( <Provider store={store}> ... </Provider> ); }; export default App 复制代码
配置持久化
当我们做完上部操作后,dva就已经配置好了,但此时会有一个问题,那就是页面刷新会使dva
中的数据初始化,这里建议移动端做持久化配置
插件: dva-model-persisit
引入时注意
本地存储 dva-model-persist/lib/storage
会话存储 dva-model-persist/lib/storage/session
建议使用 会话存储
并且 需要在 app.start()之前进行配置
mport { persistEnhancer } from 'dva-model-persist'; import storage from 'dva-model-persist/lib/storage/session'; function createApp(opt) { ... app.use({ extraEnhancers: [ persistEnhancer({ key: 'model', storage }) ], }) ... return app } 复制代码
配置好后,重新启动下项目就行了
如果有小伙伴对 dva 不太会使用,建议看看这篇文章:Dva 实战演练
路由 React-Keeper
关于 react-keeper 有这篇文章: 比React-Router更适合你的单页面路由器
这里就不多废话了,直接配置就好
参数配置
index : 入口组件
miss : 地址不匹配时渲染的组件
cache : 缓存标记
redirect : 重定向地址 (当组件满足渲染条件时才会执行)
path : 匹配地址规则
component :要匹配的组件
loadComponent : 动态加载组件
enterFilter : 挂载过滤器
leaveFilter : 卸载过滤器
offDirtyCheck : 关闭脏检查。React-Keep会默认启用脏检查,以避免地址变更时不必要的渲染
<HashRouter> <div> <Route index component={Home} path='/'/> <Route cache component={Host} path='/host' /> <Route miss path='/aboutus' component={AboutUs}/> <Route path='/other' redirect='/redirect'/> </div> </HashRouter> 复制代码
简单配置
我们希望有单独一个路由文件,然后进行配置,所以结构上为 数组,我们直接穿件文件 src/router
大致结构长这样
import _404Page from '@/pages/_404'; import Index from '@/pages/Index'; const routes = [ { path: '/', // 路径地址 index: true, //第一个页面 index 为 true title: 'react-mobile-Domesy', // 页面标题 component: Index, // 引入的组件 }, { path: '/Content', component: Content }, ... { // 可以配置些其他公共页面,如404页面 path: '/_404', miss: true, component: _404Page }, ] 复制代码
之后我们需要,把他扔到 App.tsx
文件中,并单独创个 Router
组件来接收
import React from 'react'; import { Provider } from 'react-redux' import './App.less'; import Router from './utils/Router'; import models from './models' import dva from './utils/dva' import routes from './router'; const app = dva.createApp({ models, }) const store = app.getStore() const App: React.FC = () => { return ( <Provider store={store}> <div className="App"> <Router routes={routes} /> </div> </Provider> ); }; export default App; 复制代码
最后,我们只需要将 Router 这个组件写好,将接收到的数组遍历下就行了
import React, { Component } from 'react'; import { Modal } from '@/utils'; import { HashRouter as Router, Route } from 'react-keeper'; class Index extends Component { constructor(props){ super(props); this.state = { routes: [] } } render(){ const { routes } = this.props; return ( <Router> <div> { routes.map((item, index) => ( <Route ..., component={item.component} // 有问题 key={index} /> )) } </div> </Router> ) } } export default Index 复制代码
这里有一个致命的缺陷,component 不支持 Hook,也就是不支持函数式写法,必须 class组件或者无状态的函数式组件,但后面包裹的第二层可以使用Hook
其实除了这一个问题以外,我们希望 react-keeper
还可以动态加载,既然要动态加载就需要使用到loadComponent
这个参数了~
为了解决上述两个问题,我想了一个方法(不一定是最好的解决方法),写一个公共页面,把 item.component 当参数传入下去,这就就可以使用Hooks的同时,我们也可以通过这个公共页面做一些有关项目的整体操作
在 src/pages
下创建 Home.jsx
import React, { Component } from 'react' class Home extends Component { render() { const Component = this.props.children return ( <> <Component /> </> ) } } export default Home 复制代码
这样就ok了,同时我们在这个页面可以创建一些公共的组件,比如说水印,评价模块,等~
差点忘了, item.component
需要通过 children
这个属性传递
最后,在附上配置完后 Router
模块
import React, { Component } from 'react'; import { Modal } from '@/utils'; import { HashRouter as Router, Route } from 'react-keeper'; import Home from '@/pages/Home'; /** * @module 路由模块 * * @param routes 数组,包含所需要的每项 * @param exact 是否完全匹配(默认完全匹配) * cache属性可以添加属性值,React-Keeper支持的属性值有root(default)、parent。 * @param catch 页面缓存 支持两种形式 一种是root(默认),这种为永久缓存,只要根组件不解绑,页面将永久缓存,另一种是parent为父组件缓存,在父组件不解绑的情况下会维持缓存状态 * @param path 页面路径 * @param title 页面标题 * @param component 组件 */ class Index extends Component { constructor(props){ super(props); this.state = { routes: [] } } componentDidMount = () => { const { routes } = this.props; if(Object.keys(routes).length === 0){ Modal.alert('暂未配置路由, 请去配置') return; } } render(){ const { routes } = this.props; return ( <Router> <div> { routes.map((item, index) => ( <Route exact={item.exact ? false : true} index={item.index ? true : false} miss={item.miss ? true : false} path={item.path} cache={item.cache ? item.cache === "parent" ? "parent" : "root" : false} children={item.component} loadComponent = {(callback) => { item.title ? document.title = item.title : ''; callback(Home) }} key={index}/> )) } </div> </Router> ) } } export default Index 复制代码
最后
dva 和 react-keeper 就配置成功了,这样一个开箱即用的 React 移动端框架就配置完成了~
作者:Domesy
链接:https://juejin.cn/post/7054072972968984613