在线考试系统 - 毕业设计

在互联网连接一切的风潮之下,对于考试系统,也有很多人搭建一套符合自己需求的在线系统,但是却苦于一直没有好的开源项目,最后不得不购买高昂的 SaaS 在线考试系统,在此推荐几款好用的在线考试开源项目,供大家交流讨论。

文件:590m.com/f/25127180-497684501-f2b1e1(访问密码:551685)

以下内容无关:

-------------------------------------------分割线---------------------------------------------

在recat中不使用redux 时遇到的问题
在react中组件通信的数据是单向的,顶层组件可以通过props属性向下层组件传递数据,而下层组件不能向上层组件传递数据,要实现下层组件修改数据,需要上层组传递修改数据的方法到下层组件,当项目越来越的时候,组件之间传递数据变得越来越困难

img

在react中加入redux 的好处
使用redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件之间传递数据困难的问题

img

使用redux
下载redux
npm install redux react-redux
redux 工作流程
组件通过 dispatch 触发action
store 接受 action 并将 action 分发给 reducer
reducer 根据 action 类型对状态进行更改并将更改后的数据返回给store
组件订阅了store中的状态,store中的状态更新会同步到组件
img

使用react+redux实现计数器
创建项目,并安装 redux

如果没有安装react脚手架则执行这条命令安装reate脚手架

npm install -g create-react-app

创建reate项目

create-react-app 项目名

进入项目

cd 项目名

安装 redux

npm install redux reate-redux
引入redux,并根据开始实现的代码在react中实现计数器
//index.js
import React from ‘react’;
import ReactDOM from ‘react-dom’;
import App from ‘./App’;
import { createStore } from ‘redux’;

const initialState = {
count: 0
}
function reducer(state = initialState, action) {
switch (action.type) {
case ‘increment’:
return {
count: state.count + 1
}
case ‘decrement’:
return {
count: state.count - 1
}

default:
  return state

}
}
const store = createStore(reducer)

const increment = {
type: ‘increment’
}

const decrement = {
type: ‘decrement’
}

function Count() {
return


<button onClick={() => store.dispatch(increment)}>+
{store.getState().count}
<button onClick={() => store.dispatch(decrement)}>-

}

store.subscribe( () => {
console.log(store.getState())
ReactDOM.render(
<React.StrictMode>

</React.StrictMode>,
document.getElementById(‘root’)
);
})

ReactDOM.render(
<React.StrictMode>

</React.StrictMode>,
document.getElementById(‘root’)
);
明显以上方式虽然可以实现计数器的功能,但在实际项目中肯定不能这样使用,因为组件一般都在单独的文件中的,这种方式明显在其他组件中并不能获取到Store。

计数器案例代码优化-让store全局可访问
为了解决Store获取问题需要使用react-redux来解决这个问题,react-redux给我们提供了Provider组件和connect方法

Provide 组件
是一个组件 可以吧创建出来的store 放在一个全局的地方,让组件可以拿到store,通过provider组件,将 store 放在了全局的组件可以够的到的地方 ,provider要求我们放在最外层组件

connect
connect 帮助我们订阅store中的状态,状态发生改变后帮助我们重新渲染组件

通过 connect 方法我们可以拿到 store 中的状态 把 store 中的状态映射到props中

通过 connect 方法可以拿到 dispatch 方法

connect 的参数为一个函数 这个函数可以拿到store中的状态,要求我们这个函数必须返回一个对象,在这个对象中写的内容都会映射给组件的props属性

connect 调用后返回一个函数 返回的这个函数继续调用需要传入组件告诉connect需要映射到那个组件的props

新建 Component 文件夹、创建 Count.js 文件
import React from ‘react’

function Count() {
return


<button onClick={() => store.dispatch(increment)}>+
{store.getState().count}
<button onClick={() => store.dispatch(decrement)}>-

}

export default Count
引入 Provider 组件放置在最外层,并制定store
ReactDOM.render(
// 通过provider组件 将 store 放在了全局的组件可以够的到的地方 provider要求我们放在最外层组件
,
document.getElementById(‘root’)
);
引入 connect 方法 根据 connect 的使用来包裹组件
const mapStateProps = state => ({
count: state.count,
a: ‘1’
})
// connect 的参数为一个函数 这个函数可以拿到store中的状态,要求我们这个函数必须返回一个对象,在这个对象中写的内容都会映射给组件的props属性
// connect 调用后返回一个函数 返回的这个函数继续调用需要传入组件告诉connect需要映射到那个组件的props
export default connect(mapStateProps)(Count)
改造 Count 组件把 action 复制到该文件中
const increment = {
type: ‘increment’
}

const decrement = {
type: ‘decrement’
}
function Count({count,dispatch}) {
return


<button onClick={() => {dispatch(increment)}}>+
{count}
<button onClick={() => {dispatch(decrement)}}>-

}
现在项目已经可以运行了但是Count组件中的 提交Action的那一长串代码影响视图的可读性,所以代码还是需要优化

计数器案例代码优化-让视图中的代码可读性更高
我们希望视图中直接调用一个函数这样视图代码可读性强,这个需要利用connect的第二个参数,第二个参数是一个函数,这个函数的形参就是dispatch方法,要求这个函数返回一个对象,返回的这个对象中的内容都会映射到组件的props属性上

申明一个变量为connect中的第二个参数,在这个变量中返回执行不同action操作的对象
// connect 的第二个参数 这个参数是个函数 这个函数的形参就是dispatch方法 要求返回一个对象 这个对象中的属性会被映射到组件的props上
const mapDispatchToProps = dispatch => ({
increment (){
dispatch({
type: ‘increment’
})
},
decrement (){
dispatch({
type: ‘decrement’
})
}
})

// connect 的参数为一个函数 这个函数可以拿到store中的状态,要求我们这个函数必须返回一个对象,在这个对象中写的内容都会映射给组件的props属性
// connect 调用后返回一个函数 返回的这个函数继续调用需要传入组件告诉connect需要映射到那个组件的props
export default connect(mapStateProps, mapDispatchToProps)(Count)
在组件中结构props在视图中直接绑定事件
function Count({count,increment,decrement}) {
return


+
{count}
-

}
通过这次优化我们发现 调用 dispatch 触发action 的方法的代码都是重复的,所以还需要继续优化

优化调用 dispatch 触发action 的方法的重复代码简化
利用 bindActionCreators 来简化 dispatch 触发 action的操作,bindActionCreators来帮助我们生成执行action动作的函数

bindActionCreators 有两个参数,第一个参数为 执行action的对象,第二个参数为 dispatch方法

分离action操作,新建store/actions/counter.actions.js文件把执行action操作单独放在这个文件并导出
export const increment = () => ({type: ‘increment’})
export const decrement = () => ({type: ‘decrement’})
在Count.js中导入关于计数器的action,用bindActionCreators方法来生成dispatch执行action函数
import { bindActionCreators } from ‘redux’
import * as counterActions from ‘./…/store/actions/counter.actions’

const mapDispatchToProps = dispatch => (bindActionCreators(counterActions, dispatch))
// connect 的参数为一个函数 这个函数可以拿到store中的状态,要求我们这个函数必须返回一个对象,在这个对象中写的内容都会映射给组件的props属性
// connect 调用后返回一个函数 返回的这个函数继续调用需要传入组件告诉connect需要映射到那个组件的props
export default connect(mapStateProps, mapDispatchToProps)(Count)
代码优化到这里我们发现,redux的代码与组件融合在一起,所以我需要拆分成独立的,为什么要抽离redux呢?因为我们要让我们的代码结构更加合理

上一篇:iOS 多线程与线程安全(二)


下一篇:Redux从设计到源码