基于react的前端项目开发和实战总结(umi框架)
本文介绍了基于react的前端项目开发方法及常用基础知识,实战案例主要是基于umi框架。
主要内容包括:
1)Umi项目目录结构约定;
2)核心概念如Umi框架、Dva状态管理及其与React的配合使用;
3)React与Vue在数据流、组件通信等方面的差异;
4)开发技能要点,包括Dva模型定义、组件编写、父子组件通信方法;
5)状态管理机制对比(put、localStorage、useState)。
重点阐述了在Umi项目中如何通过Dva管理状态、实现组件间通信,以及React单向数据流下父子组件传值的特点。
一、目录结构
umi结构
|- src/
|- |-pages/ # 页面目录(约定式路由)
|- |-models/ # dva 状态模型【掌握通信方法和写法】
|- |-components/ #自定义组件【子组件和父组件-嵌套使用及通信方式;组件编写方法】
|- |-layouts/ # 全局布局组件
|- |-assets/ # 字体和图片
|- |-config/ # 接口定义和静态数据
|- |-app.tsxe # 应用入口配置
|- |-.umi #自动生成的运行时文件
|- |-.config/
|- |- |-routes.ts #路由配置(可选)
|- |- |-umirc.ts # umi配置文件【环境配置时用到】
|- |- package.json【项目元数据和配置信息:scripts 脚本; gitHooks 钩子;dependencies 依赖】|- |--tsconfig,json # 编译选项
- README.md
二、基本概念
1、umi框架
umi是一个由蚂蚁金服推出的 React 应用框架,旨在简化React应用的开发流程,提供开箱即用的工程化能力和插件化扩展机制。
2、dva 框架
dva是一个状态管理框架,它整合了React、Redux和Redux-saga,帮助开发者更轻松地管理应用的状态和处理异步逻辑。
(1)redux 状态管理
通过model组织状态、更新逻辑和副作用状态的容器,包含 state(状态)、reducers(同步更新)和 effect(异步操作)等;
(2)Redux Saga,支持通过 effects 处理异步操作;
3、umi与 dva 的关系
(1)umi是框架,dva 是状态管理库;
umi提供路由、构建、插件等整体框架能力,而 dva 专注于状态管理(类似 Redux+saga 的封装);
(2)umi集成 dva:通过插件 @umijs/plugin-dva,umi可以无缝集成 dva 的 model 机制简化状态管理。示例:在 umi项目中启用 dva 插件后,开发者只需在 src/models 目录下编写 dva 的 model 文件,umi会自动将其注入到应用中。
4、react 和 vue 的区别
(1)vue 的双向绑定:通过 v-mode:直接同步表单输入与状态,减少样板代码,适合表单密集场景(如后台管理系统)
(2)react 的单向数据流强调数据流的可预测性,适合复杂状态逻辑(如大型应用、需要严格调试的项目)。
因此父子组件中,需要子组件改变数据的场景中,父组件可以传给子组件方法,在model中方法与数据绑定,子组件调用方法便改变了数据;而不能直接传数据给子组件。
而vue在父子组件中,只能传递数据,不能传递方法。子组件改变数据,因为双向绑定,数据流向是双向的,父组件数据随之自动改变
(3)vue要手动配置路由,react通过页面目录自动映射
5、页面开发主要技术概念
单页面开发主要掌握dva通信和父子组件通信方法,其他的组件引入使用可参考开发手册;
(1)model:状态和业务逻辑的容器,包含state(状态)、reducers(同步更新)和effects(异步操作)。
(2)componentReact 组件,通过 connect 方法与 Model 绑定,访问状态或触发更新
三、主要开发技能(重要)
如下是示例页面的开发
|- src/
|- |-pages/
|- |- |-desk/nstitution-switch
|- |- |- |-index.js
|- |- |- |-models/
|- |- |- |- |-institution_switch_model.js
1、路由定义
在 umi 下,根据文件目录自动生成路由
如图所示:
路由地址:/desk/institution-switch
2、dva
(1)institution_switch_model.js是model
(src/pages/desk/institution-switch/models/institution_switch_model.js
(2)index.js 是组件
(3)两者通过 dva().connect 实现绑定
3、model
model 定义方法和用到的数据,并通过 dva 进行状态管理。文件结构有点类似 vue 的全局文件存储 state 管理。
主要分为:state、reducers、effects、subscriptions
- namespace:和文件夹同名(model 命名)
- state:变量
- reducers: 用于更新 state 的内容,通常被 effects 的方法调用
如:
reducers: {update (state, { payload: obj} ) {return {...state,...obj }}
}
effect使用方法:
yield put({ type: 'update’, payload: { switchConfiglist: resultData|| []} })
4、effects :
操作的方法,提供给组件调用,改变state的数据
*querySwitchConfigList ({ payload: obj}, { put} ) {const resultData = yield.post(QUERY INSTITUTION SWITCH CONFIG LIST, obj)}
注意:
(4.1) 前面要加*
(4.2)命名方法:
{payload: obj} ,用于提取 payload 属性幷重命名为 obj
{payload},用于提取 payload 属性,并且保持其名称不变
(4.3)effects 里的方法相互调用
yield put({
type:方法名,
payload:{***},
})
区别于 vue 的直接 this.方法名
5、subscriptions
监听路由变化和定时器
subscriptions 在 dva(基于 Redux 和 Redux-Saga 的数据流方案)中用于订阅一些数据源,比如路由变化、Websocket 消息、定时器等,并根据需要 dispatch action。在代码中,subscriptions 主要用于监听路由变化action 以更新 state,并在进入特定路径时 dispatch一个action 以更新 state。
示例:
subscriptions: {setup ({ dispatch, history}) {history.listen(({pathname))=>{if (pathname.indexOf(‘/desk/nstitution-switch’)>1){dispatch({type: 'update', payload: { switchConfigList: []),})}}),}},
如上访问/desk/institution-switch 页面(列表页面),先清空教据
6、组件
[代码主要组成部分: ]
function RuleInfo({dispatch, 对应model定义的变量switchConfigList,modelData1..}){
//数据定义(初始化绑定 model)
const data1 =modelData1(对应model定义的变量)
...
// 数据定义(自定义)
const [data2, setData2]= useState(false)
// 方法定义(绑定model)
// type为路由路径,由文件路径自动映射,加上 model名称。
const functionA = (param) => {
dispatch( {type:’rule info mode/queryCommonRuleBusinessOptions’,
payload: { param }})
}
// 方法定义(自定义)
.......
}
//刚进入页面时执行的方法,类似vue的create()
useEffect(()=>{
functionA()}, [])
})
// 组件页面布局
return (
<div>
<父组件>
<子组件
propa = {data1 }
propb = (data2 }
propc = {functionA }
</子组件>
</父组件>
</div>
)
}
//用 dva 的 connect 将组件和 model 绑定
const mapStateToProps = (state)=>{
// 变量引用 model 的 state,变量命名和文件开头的入参一样
const { switchConfigList }= state.institution_switch
// 方法引用
const tableLoading state.loading.effects['institution-switch/quenySwitchConfigList
//变量命名和本文件开头的入参一样
return {tableLoading,switchConfigList,}
}
export defaut connect(mapStateToProps)(SwitchConfigPage);
注意:
(1) model 的 effect 调用方法是 yield put(type:方法名)
组件调用方法是 dspatch(type:路径)
(2) 父子组件里赋值传递的不能直接是 effect 的,还要在数掘定义和方法定义中重新定义,初始化成 effect 的值并绑定。
(3) 父子组件传递的可以是变量和方法,在 vue 里只能传递变量;
***为什么传递方法呢***
方法在 model 里,可以操作 state 数据,相当于方法和激据绑定在 react 数据是单向流动,只能从父组件流向子组件,所以子组件里的数倒改动影响不了父组件;
因此此时就要传递方法,因为方法和数据定,子组件调用方法后,方法再改变数据;
区别于 vue,vue 是动态双向绑定,子组件数据通过prop 绑定后,子组件对数据的改动,便是对全局父组件数据的改动。
7、父子组件的通信
上述讲了 dva 之间的通信,接下来是父子组件的
function Rulelnfo ({
propa,propb,propc(父组件里插入子组件时,对应左边的命名)
}){
// 自定义数据
const test1;
// 自定义方法
const testfun1,
return (
<div>
<二级子组件
twoComponentdata1={test1}
twoComponentData2={propa}
twoComponentFunction2={propb}
/>
</div>
注意:
和 dva 的数据传递不同,dva 和 model 之间传递数据(右边的),先要在组件里面定义自己的变量,然后绑定到值 model的变量,有中间的一步,不直接使用。
但是父子组件的通信,可以直接使用,方法和变量都可以直接便用组件传过来的,没有中间的一步;也可以使用自定义的方法变量。
四、其他问题
1、useState ,locaiState , useEffect
useState 组件实例内存;localstate 硬存;
useState 和 useEffect 的作用
useState 钩子用于在函数组件中添加状态。它允许你声明一个状态变量,并提供一个用于更新该状态的函数。这是 React函数组件中管理状态的主要方式。
useEffect 钩子用于在函数组件中执行副作用操作。副作用操作包括数据获职、订阅设置手动修改 DOM 等。
这两个钩子是 React 函数组件开发中非常基础和重要的工具。
在 React 函数组件中,如果直接给一个状态变量(如 switchChecked)赋值,而不是通过 useState 或其他 React 提供的状态管理方法来更新状态,React 将无法跟踪状态的变化并触发组件的重新渲染。这会导致 UI不会反映出状态的最新值。
2、存储机制 put、localStorage 和 useState
put、localstorage 和 useState 分别对应不同级别的存储机制,具体如下:
存储级别:
应用级别:put 用于在应用中全局管理状态,适用于需要在多个组件之间共享的状态。put 是 Redux 或 Redux-Saga 中用于 dispatch action 的函数,用于在应用中全局管理状态。
客户端级别:localstorage 存储在用户的浏览器中,适用于需要在多个页面或会话之间共享的数据。
组件级别:useState 用于在单个组件内部管理状态,适用于局部状态管理。
3、方法调用:
在典型的 Redux-Saga 架构中
(1).组件 dispatch-个 action(如'main/getuserInfo')
(2).saga 监听这个 action,执行 API 调用
(3).saga收到响应后:dispatch个新actio
(如'main/getuserInfosuccess')
(4).Reducer 处理这个新 action,将数据存储在 store 中
(5).组件通过 mapstateToProps 从 store 中获取数据