最近一直在学React,它是一款前端的,用于构建用户界面的JavaScript库,它的好处就是将界面拆分成一个个组件,然后进行组合,比较适合于模块化编程。但是组件之间的数据管理却没有一个好的解决方案,特别是对于组件之间层次比较深,数据之间传递还是很麻烦的,所以有了Redux,它主要职责就是多页面数据存储,使用时候会构建一个中心store,所有数据都是存放于state中,而state存放于store中,在界面中使用只需要从store中拿数据就可以了。由于学了一段时间React,所以希望将学到的东西以Demo的形式进行展示,方便后续复习使用。
这个Demo是一款简易的TodoList,功能比较简单,但是常用的功能都有,所以比较适合入门学习,下面是它的演示
输入事项,点击提交可以添加到列表的事项中,点击delete删除对应的列表项,就是这么简单
用到的库
用到的框架引入方式
npm install 框架名 --save // --save可以让下载下来的文件相关信息写入package.json中
或
yarn add 框架名
两种引入方式都可以,如果网络不好需要配置taobao镜像,或者,我都是直接的
为了以后拷贝方便,我将导入语句的源码都拷贝过来了(包括后面的代码)
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
import { Provider } from 'react-redux'
import store from './store'
const App = (
//获取store,Provide组件作用是将store提供给子组件
<Provider store={store}>
<TodoList />
</Provider>
)
//整个项目的根组件,挂载在root节点下,通过ReactDOM.render进行渲染
ReactDOM.render(App, document.getElementById('root'));
import React from 'react';
import { Input, Button, List } from 'antd';
import { connect } from 'react-redux'
import {getInputChangeAction,handleClickAction,handleDeleteAction} from './store/actionCreates'
import 'antd/dist/antd.css'
/**
* ui组件可以定义为无状态组件,能够有效提供页面性能
*/
const TodoList = (props) => {
const { inputValue, list, changeInputValue, handClick, handleDelete} = props;
return (
<div style={{ marginTop: '10px', marginLeft: '10px' }}>
<div>
<Input value={inputValue}
style={{ width: '300px', marginRight: '10px' }}
onChange={changeInputValue}/>
<Button type="primary"
onClick={handClick}>提交</Button>
</div>
<List
bordered
style={{ marginTop: '10px', width: '300px' }}
itemLayout="horizontal"
dataSource={list}
renderItem={(item, index) => (
<List.Item
actions={[<span onClick={e => {
e.preventDefault();
handleDelete(index)
}} >delete</span>]}>
<div style={{ width: '260px' }}>{item}</div>
</List.Item>
)}
/>
</div>
);
}
//1
const mapStateToProps = (state) => {
return {
inputValue: state.todo.inputValue,
list: state.todo.list
}
}
//2
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue(e){
const action = getInputChangeAction(e.target.value)
dispatch(action)
},
handClick: function(e){
const action = handleClickAction()
dispatch(action);
},
handleDelete: function(e){
const action = handleDeleteAction(e)
dispatch(action)
}
}
}
/**
* connect组件连接之后就是容器组件
*/
export default connect(mapStateToProps, mapDispatchToProps)(TodoList)
页面主要逻辑代码都在这块,整个js文件主要由两部分组成,其一为无状态组件TodoList,定义为无状态组件可以提高一定的性能,避免了有状态组件执行生命周期方法等耗时,其二为与store进行连接的部分connect。组件搭建使用的是AntD,这样可以减少页面的布局时间,connect的作用是将TodoList与store进行连接,这样TodoList就可以使用store中的数据了,要想使用和对store中的数据进行更新还需要了解connect的两个参数mapStateToProps,mapDispatchToProps,这是两个方法返回值为对象。mapStateToProps作用是映射store中state给props,这样就可以通过props应用state数据了,但是还是需要自己去完成映射部分的代码。demo中代码为注释1。mapDispatchToProps作用是将Dispatch映射给props,然后就可以使用Dispatch去更新store中的数据,同样映射代码还需要自己去完成,demo中代码为注释2,一切都是套路,具体照着代码模板修改就可以了。
接下来就来看下store中相关代码的实现,也是套路。
import { createStore, compose } from 'redux';
import reducer from './reducer'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer, composeEnhancers());
export default store;
这部分是store的创建部分,也是套路,值得一提的是这里引入了redux-devtools-extension,这是一个浏览器调试redux的工具,大致界面如下
这工具还是很牛逼的,它可以很方便看state中的数据,同时还存有该页面中操作过的记录,然后可以回放页面记录。具体可以安装之后探索使用。
import { combineReducers } from 'redux';
import { reducer as todoReducer } from './todoReducer';
export default combineReducers({
todo: todoReducer
})
这是所有reducer的总文件,它存放所有子模块的reducer文件,当一个项目模块很多的时候就需要将reducer进行分离,然后通过combineReducers结合。我们可以看到它引用了todoReducer,后面查看
import {
CHANGE_INPUT_VALUE,
ADD_ITEM,
DELETE_ITEM
} from './actionTypes'
export const getInputChangeAction = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
export const handleClickAction = () => ({
type: ADD_ITEM
})
export const handleDeleteAction = (value) => ({
type: DELETE_ITEM,
value: value
})
action的管理,需要使用的时候直接从这里引入。
export const CHANGE_INPUT_VALUE = 'change_input_value'
export const ADD_ITEM = 'add_item'
export const DELETE_ITEM = 'delete_item'
action相关常量
import reducer from './reducer'
export { reducer }
这个文件只是为了方便导入reducer,在别的地方引用todoReducer中reducer文件时可以减少路径的书写。
import {
CHANGE_INPUT_VALUE,
ADD_ITEM,
DELETE_ITEM
} from '../actionTypes'
const defaultState = {
inputValue: '',
list: []
}
export default (state = defaultState, action) => {
if(action.type === CHANGE_INPUT_VALUE){
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}else if(action.type === ADD_ITEM){
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = ''
return newState;
}else if(action.type === DELETE_ITEM){
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.index, 1)
return newState;
}
return state;
}
todoList中reducer数据管理的地方,注意在导出的时候这个函数是一个纯函数,我们不能直接改变state中的值,我们需要深拷贝state,然后通过拷贝的state去操作数据,最后将state返回。
这就是todoList所用相关代码,方便以后学习拷贝使用。
下载地址
1.React 16.4 开发简书项目
从零基础入门到实战
2.react官网