使用react+redux实现方式计数器功能及遇到问题实用指南

作者:袖梨 2026-08-24

平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“采用react+redux实现方法计数器功能及遇到问题”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。

实际处理时,Redux,本身就是一个单纯的状态管理者,我们不追溯它的历史,从采用角度来说:它提供一个全局的对象store,store中包含state对象用以包含所有应用数据,同时且store提供了一些reducer方法。这些方法能够自定义,采用调用者得以改变state的值。state的值仅为只读,如果需更改则必须只能借助reducer。

Redux

  • 核心对象:store
  • 数据存储:state
  • 状态更新提交接口:==dispatch==
  • 状态更新提交参数:带type和payload的==Action==
  • 状态更新计算:==reducer==
  • 限制:reducer必须是纯函数,不兼容异步
  • 特性:兼容中间件

React + Redux

在recat中不采用redux 时遇到的问题

从实现思路看,在react中组件通信的数据是单向的,顶层组件能够借助props属性向下层组件传递数据,而下层组件不能向上层组件传递数据,要实现下层组件修改数据,需上层组传递修改数据的方法到下层组件,当项目越来越的时候,组件之间传递数据变得越来越困难

在react中加入redux 的好处

实际处理时,采用redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件之间传递数据困难的问题

采用redux

下载redux


npm install redux react-redux

redux 工作流程

  1. 组件借助 dispatch 触发action
  2. store 接受 action 同时将 action 分发给 reducer
  3. reducer 根据 action 类型对状态进行更改同时将更改后的数据得到给store
  4. 组件订阅了store中的状态,store中的状态更新会同步到组件

采用react+redux实现计数器

1.新建项目,并安装 redux


# 如果没有安装react脚手架则执行这条命令安装reate脚手架
npm install -g create-react-app
# 创建reate项目
create-react-app 项目名
# 进入项目
cd 项目名
# 安装 redux
npm install redux reate-redux

2.引入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 <div>
    <button onClick={() => store.dispatch(increment)}>+</button>
    <span>{store.getState().count}</span>
    <button onClick={() => store.dispatch(decrement)}>-</button>
  </div>
}

store.subscribe( () => {
  console.log(store.getState())
  ReactDOM.render(
    <React.StrictMode>
      <Count />
    </React.StrictMode>,
    document.getElementById('root')
  );
})

ReactDOM.render(
  <React.StrictMode>
    <Count />
  </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 <div>
        <button onClick={() => store.dispatch(increment)}>+</button>
        <span>{store.getState().count}</span>
        <button onClick={() => store.dispatch(decrement)}>-</button>
    </div>
}

export default Count

引入 Provider 组件放置在最外层,同时制定store


ReactDOM.render(
  // 通过provider组件 将 store 放在了全局的组件可以够的到的地方 provider要求我们放在最外层组件
  <Provider store={store}><Count /></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 <div>
        <button onClick={() => {dispatch(increment)}}>+</button>
        <span>{count}</span>
        <button onClick={() => {dispatch(decrement)}}>-</button>
    </div>
}

实际处理时,现在项目已经能够运行了但是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 <div>
        <button onClick={increment}>+</button>
        <span>{count}</span>
        <button onClick={decrement}>-</button>
    </div>
}

从实现思路看,借助这次优化我们发现 调用 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呢?因为我们要让我们的代码结构更加合理

重构计数器,把redux相关代码抽离

把reducer函数抽离为单独的文件、把新建store抽离到单独的文件中

结合项目来看,因为在reducer 和 actions中我们都写了字符串,但是字符串没有提示所以我们把字符串定义成常量防止我们出现单词错误这种低级错误,新建 src/store/const/counter.const.js 文件


export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

新建 src/store/reducers/counter.reducers.js 文件把 reducer 函数抽离到此文件中


import { INCREMENT, DECREMENT} from './../const/counter.const'
const initialState = {
    count: 0
}
// eslint-disable-next-line import/no-anonymous-default-export
export default (state = initialState, action) => {
    switch (action.type) {
        case INCREMENT:
            return {
                count: state.count + 1
            }
        case DECREMENT:
            return {
                count: state.count - 1
            }

        default:
            return state
    }
}

更改actions中的字符串为引入变量


import { INCREMENT, DECREMENT} from './../const/counter.const'

export const increment = () => ({type: INCREMENT})
export const decrement = () => ({type: DECREMENT})

从实现思路看,新建src/store/index.js文件,在这个文件中新建store 同时导出


import { createStore } from 'redux';
import reducer from './reducers/counter.reducers'

export const store = createStore(reducer)

在引入store的文件中改变为冲项目中store文件中引入store


import React from 'react';
import ReactDOM from 'react-dom';
import Count from './components/Count';
import { store } from './store'
import { Provider } from 'react-redux'
/**
 * react-redux 让react 和 redux 完美结合
* Provider 是一个组件 可以吧创建出来的store 放在一个全局的地方 让组件可以拿到store
* connect 是一个方法
 */


ReactDOM.render(
  // 通过provider组件 将 store 放在了全局的组件可以够的到的地方 provider要求我们放在最外层组件
  <Provider store={store}><Count /></Provider>,
  document.getElementById('root')
);

为action 传递参数,对计数器案例做扩展

结合项目来看,这个计数器案例已经实现了点击按钮加一减一操作了,现在有个新需求我们需加减一个数值比如加五减五

这就需对action传递参数了

在视图中按钮绑定函数传入参数


function Count({count,increment,decrement}) {
    return <div>
        <button onClick={() => increment(5)}>+</button>
        <span>{count}</span>
        <button onClick={() => decrement(5)}>-</button>
    </div>
}

在dispacth执行action动作时接受参数同时传入到action中


export const increment = payload => ({type: INCREMENT, payload})
export const decrement = payload => ({type: DECREMENT, payload})

在reducers中接收参数并作相应处理


export default (state = initialState, action) => {
    switch (action.type) {
        case INCREMENT:
            return {
                count: state.count + action.payload
            }
        case DECREMENT:
            return {
                count: state.count - action.payload
            }

        default:
            return state
    }
}

原文地址:(链接已移除)

到此这篇关于在react中采用redux同时实现计数器案例的文章就介绍到这了,更多相关react redux实现计数器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多兼容脚本之家!

您可能感兴趣的文章:
  • React/Redux应用采用Async/Await的方法
  • ReactNative中采用Redux架构总结
  • 详解如何优雅地在React项目中采用Redux
  • 轻松介绍react redux的中间件的采用
  • 优雅的在React项目中采用Redux的方法
  • React 中采用 Redux 的 4 种写法小结
  • 一文详解React Redux采用方法

相关文章

精彩推荐