react-redux的基础使用

react-redux的基础使用,第1张

原文链接

一、安装

项目基于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使用者更方便的函数方法,让reduxreact中的使用更加美丽而已。

二、目录结构

一般的使用习惯是在src目录下使用一个store目录在管理整个redux的实例。
同时,基于不同功能类型,创建不同的子目录。
例如:src/constant目录用来存放定义常量的文件;src/actions目录存放定义了redux action或者redux actionCreator的文件;src/reducers目录存放所有的reducer文件。
并且在src这一级下,还会有一个index.js文件用来createStore和统一导出。

三、示例

下面做一个小案例来使用一下reduxreact-redux

拥有一个输入框来输入内容,一个发送按钮,一个清除按钮。redux维护一个list数组,当点击发送按钮,就将输入框的内容push进list数组,点击清除按钮就清空list。展示list
1. 定义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了。

3. 定义reducer

在前面我们定义了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已经创建好了,那我们如何去使用呢。

5. Provider

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接受两个参数,mapStateToPropsmapDispatchToProps,最后再包裹我们的展示组件。

7. 效果

8. 优化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同名的函数映射。

注:本博客仅供个人学习,如有错误、侵权敬请指出。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/940977.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存