原文链接
一、安装项目基于vite
创建
yarn create vite pro_name --template react
安装redux
依赖
npm install redux react-redux
//或者
yarn add redux react-redux
要使用react-redux
还是需要安装redux
的,react-redux
只是提供了一些对react
使用者更方便的函数方法,让redux
在react
中的使用更加美丽而已。
一般的使用习惯是在src
目录下使用一个store
目录在管理整个redux
的实例。
同时,基于不同功能类型,创建不同的子目录。
例如:src/constant
目录用来存放定义常量的文件;src/actions
目录存放定义了redux action
或者redux actionCreator
的文件;src/reducers
目录存放所有的reducer
文件。
并且在src
这一级下,还会有一个index.js
文件用来createStore
和统一导出。
下面做一个小案例来使用一下redux
和react-redux
。
拥有一个输入框来输入内容,一个发送按钮,一个清除按钮。redux维护一个list数组,当点击发送按钮,就将输入框的内容push进list数组,点击清除按钮就清空list。展示list1. 定义type常量
redux
是基于action
去触发数据改变的,对于每个action
必须拥有一个type
属性来确定action
的行为类型,而这个type
就相当于action
的名称一样。
type
一般为字符串类型,为了方便后续编程,通常将这种字符串定义为常量。
这种方式可以简化后续书写,以及确保使用安全,因为字符串是很难去检查后续书写和之前书写的一致性的。
src\store\constants\actionTypes.js
export const ADD_ITEM = 'ADD_ITEM' // 给list添加元素
export const CLEAR_LIST = 'CLEAR_LIST' // 清空list
2. 定义action和actionCreator
先来看看正常的action
长什么样。
const action1 = {type: 'ADD', value: 12}
const action2 = {type: 'REMOVE', id: 2}
const action3 = {type: 'TODO'}
其实对于绝大多数action
来说,他们的长相都是十分相似的,都有一个type
来标识他们,或者还拥有其他的属性,但在结构上是差不多的。
所以说如果按照上面的方式来定义action
,就会出现以下情况:
const action1 = {type: 'ADD_ITEM', value: 12}
const action2 = {type: 'ADD_ITEM', value: 123}
会发现我们定义的action
大部分是相同的,而他们却都只是用于触发ADD_ITEM
行为而已,太不美观。
对于这种情况,运用函数的方式来解决再好不过。
src\store\actions\list.actions.js
import { ADD_ITEM, CLEAR_LIST } from '../constants/actionTypes'
export const add_action = (value) => {
return {
type: ADD_ITEM,
value,
}
}
export const clearList_action = () => {
return {
type: CLEAR_LIST,
}
}
如上的函数就被称为actionCreator
这样对于不同的 *** 作数,我们只需要调用相应的actionCreator
,就会返回给我们包装好的action
了。
在前面我们定义了action
,他标志着要去触发某一种类型的行为,而这个行为就是在reducer
中触发。
src\store\reducers\list.reducer.js
import { CLEAR_LIST, ADD_ITEM } from '../constants/actionTypes'
const initalState = {
list: [1,2]
}
function listReducer(state = initalState, action) {
switch (action.type) {
case ADD_ITEM:
return { ...state, list: [...state.list, action.value] }
case CLEAR_LIST:
return { ...state, list: [] }
default:
return state
}
}
export default listReducer
在定义reducer
时,我们需要提供给他必要的两个参数,第一个state
用于获取上一次数据改变后的值,第二个参数就是action
了。
可以看到在其内部,基于不同的action.type
拥有不同的逻辑,return
的就是我们想要数据变化的样子。
在实际的开发中我们很可能不会只有一个
reducer
,而redux
也为我们提供了一个函数来连接这些不同的reducers
src\store\reducers\rootReducer.js
import {combineReducers} from 'redux'
import listReducer from './list.reducer'
const roorReducer = combineReducers({
listReducer,
//其他reducers,逗号分割
})
export default roorReducer
4. 创建store
现在reducer
已经定义完了,我们就要基于reducer
创建出数据仓库store
了。
src\store\index.js
import { createStore } from "redux";
import rootReducer from "./reducers/rootReducer";
const store = createStore(rootReducer)
export default store
自此,store
已经创建好了,那我们如何去使用呢。
src\App.jsx
要使用store
首先需要先将他提供给使用的地方。
react-redux
提供了一个Provider
组件来解决这个问题。我们需要让这个组件包裹我们需要用到store
的所有子组件。
src\App.jsx
import { Provider } from 'react-redux'
import store from './store'
import Handle from './components/Handle'
import List from './components/List'
function App() {
return (
<Provider store={store}>
<div className="App">
<Handle />
<List />
</div>
</Provider>
)
}
export default App
6. 容器组件,数据映射
在提供了store
后,子组件还需要将数据映射到自身的props
中才能使用。
在react-redux
提供了connect
方法解决这一问题。
src\components\List\index.jsx
import { connect } from "react-redux";
function List(props) {
return (
<div>
<ul>
{props.list.map((item, index) => <li key={index}>{item}</li>)}
</ul>
</div>
);
}
function mapStateToProps(state) {
return {
list: state.listReducer.list
}
}
export default connect(mapStateToProps)(List);
src\components\Handle\index.jsx
import { useState } from "react";
import { connect } from "react-redux";
import { add_action, clearList_action } from '../../store/actions/list.actions'
function Handle(props) {
const [va, setVa] = useState('')
const handleChange = e => {
const {value} = e.target
setVa(value);
}
const handleClick = () => {
props.add(va)
setVa('')
}
const clearClick = () => {
props.clear()
}
return (
<div>
<input type="text" onChange={handleChange} value={va}/>
<button onClick={handleClick}>发送</button>
<button onClick={clearClick}>清除</button>
</div>
);
}
function mapDispatchToProps(dispatch) {
return {
add: va => dispatch(add_action(va)),
clear: () => dispatch(clearList_action())
}
}
export default connect(null, mapDispatchToProps)(Handle);
connect
接受两个参数,mapStateToProps
和mapDispatchToProps
,最后再包裹我们的展示组件。
当我们action
足够多的时候,mapDispatchToProps
就会非常臃肿,而且在书写的时候我们都在做同一件事情:定义dispatch``action
的属性。
redux
提供了bindActionCreators
来简化这一 *** 作。
src\components\Handle\index.jsx
import { useState } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as listActions from '../../store/actions/list.actions'
function Home(props) {
const [va, setVa] = useState('')
const handleChange = e => {
const {value} = e.target
setVa(value);
}
const handleClick = () => {
props.add_action(va)
setVa('')
}
const clearClick = () => {
props.clearList_action()
}
return (
<div>
<input type="text" onChange={handleChange} value={va}/>
<button onClick={handleClick}>发送</button>
<button onClick={clearClick}>清除</button>
</div>
);
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(listActions, dispatch)
}
export default connect(null, mapDispatchToProps)(Home);
直接为我们创建基于action Creators
同名的函数映射。
注:本博客仅供个人学习,如有错误、侵权敬请指出。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)