在react中使用redux并实现计数器案例
React + Redux
在recat中不使用redux 时遇到的问题
在react中组件通信的数据是单向的,顶层组件可以通过props属性向下层组件传递数据,而下层组件不能向上层组件传递数据,要实现下层组件修改数据,需要上层组传递修改数据的方法到下层组件,当项目越来越的时候,组件之间传递数据变得越来越困难
在react中加入redux 的好处
使用redux管理数据,由于Store独立于组件,使得数据管理独立于组件,解决了组件之间传递数据困难的问题
使用redux
下载redux
npm install redux react-redux
redux 工作流程
- 组件通过 dispatch 触发action
- store 接受 action 并将 action 分发给 reducer
- reducer 根据 action 类型对状态进行更改并将更改后的数据返回给store
- 组件订阅了store中的状态,store中的状态更新会同步到组件
使用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 <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系列(五)在React中使用Redux
上一篇展示了Redux的基本使用,可以看到Redux非常简单易用,不限于React,也可以在Angular.Vue等框架中使用,只要需要Redux的设计思想的地方,就可以使用它. 这篇主要讲解在Rea ...
- 在React中使用Redux
这是Webpack+React系列配置过程记录的第六篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...
- react中使用redux简易案例讲解
为什么我想要使用redux? 前段时间初步上手了react,最近在使用react的过程中发现对于组件之间通信的需求比较迫切,尤其是在axios异步请求后端数据的时候,这样的需求是特别强烈的!举个例子: ...
- react中对于redux的封装
const createStore = (reducer)=>{ //默认的state对象 let state = {}; //将所有订阅的事件存在在这个数组中 let listeners = ...
- 在React中使用Redux数据流
问题:数据流是什么呢?为什么要用数据流? 答案:1.数据流是我们的行为与相应的抽象 2.使用数据流帮助我们明确了行为的对应的响应 问题: React与数据流的关系 1.React是纯 V 层的前端框架 ...
- 如何在非 React 项目中使用 Redux
本文作者:胡子大哈 原文链接:https://scriptoj.com/topic/178/如何在非-react-项目中使用-redux 转载请注明出处,保留原文链接和作者信息. 目录 1.前言 2. ...
- 如何优雅地在React项目中使用Redux
前言 或许你当前的项目还没有到应用Redux的程度,但提前了解一下也没有坏处,本文不会安利大家使用Redux 概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与 ...
- 优雅的在React项目中使用Redux
概念 首先我们会用到哪些框架和工具呢? React UI框架 Redux 状态管理工具,与React没有任何关系,其他UI框架也可以使用Redux react-redux React插件,作用:方便在 ...
- react中界面跳转 A界面跳B界面,返回A界面,A界面状态保持不变 redux的state方法
在上一篇文章中说过了react中界面A跳到B,返回A,A界面状态保持不变,上篇中使用的是传统的localStorage方法,现在来使用第二种redux的state方法来实现这个功能 现在我刚接触red ...
随机推荐
- Day12_62_线程的生命周期
线程的生命周期 要实现多线程,必须在主线程中创建新的线程对象. 任何线程一般都具有五种状态,即创建,就绪,运行,阻塞,终止(消亡) 新建状态:在程序中创建了一个新的线程对象后,新的线程对象便处于新建状 ...
- 一次错误使用 go-cache 导致出现的线上问题
话说一个美滋滋的上午, 突然就出现大量报警, 接口大量请求都响应超时了. 排查过程 查看服务器的监控系统, CPU, 内存, 负载等指标正常 排查日志, 日志能够响应的结果也正常. request.l ...
- 锁定项目的 node 版本
一些老项目对 node 版本是有要求的,往往使用默认的新版本包安装不上,scripts 也跑不起来. 之前就遇到过运行一个小程序项目时,根据文档来,第一步安装就出错.本着办法总比问题多的理念,来一个解 ...
- Python中sys模块的使用
目录 sys模块 sys.argv() sys.exit(0) sys.path sys.modules sys模块负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的 ...
- [转载] 关于Win7 x64下过TP保护的一些思路,内核层过保护,驱动过保护
首先特别感谢梦老大,本人一直没搞懂异常处理机制,看了他的教程之后终于明白了.在他的教程里我学到了不少东西.第一次在论坛发帖,就说说Win7 x64位下怎么过TP保护.如果有讲错的地方,还望指出.说不定 ...
- Windows核心编程 第九章 线程与内核对象的同步(下)
9.4 等待定时器内核对象 等待定时器是在某个时间或按规定的间隔时间发出自己的信号通知的内核对象.它们通常用来在某个时间执行某个操作. 若要创建等待定时器,只需要调用C r e a t e Wa i ...
- openstack虚拟机从数据库修改卷虚拟机backend操作
由于意外故障,volume-type其中一个backend后段出现性能问题,客户云主机出现卡顿. 因此临时从ceph将系统卷导出,并导入至同一个backend的另一个后端,并启动虚拟机. Nova C ...
- ColyseusJS 轻量级多人游戏服务器开发框架 - 中文手册(系统保障篇)
快速上手多人游戏服务器开发.后续会基于 Google Agones,更新相关 K8S 运维.大规模快速扩展专用游戏服务器的文章.拥抱️原生 Cloud-Native! 系列 ColyseusJS 轻量 ...
- Docker安装教程(超详细)
Docker安装教程(超详细) 欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章, 关注回复「资源」, 免费领取全网最热的Java架构师学习PDF, 转载请注明出处 http:// ...
- VS2010编写32位和64位dll环境配置,以及判断dll是多少位
前言 最近在编写dll注入程序的时候,因为想注入到系统进程,结果发现总是注入失败.自闭了好长一会发现我忘记了我的系统是64位的,系统进程也是64位的,而我编写的待注入的DLL是32位了,所以才导致失败 ...