redux基础使用与实际项目中如何应用

redux能解决啥问题?

redux的作用和vuex一样。 就是为了解决不同组件之间的通信。

基础版redux使用

首先先上一个没用redux的计算器demo

  • 定义一个state:count 作为当前的值。 可对count做加1, 减1, 奇数加1, 异步加1 的操作 ,代码如下
import React, { Component } from 'react'

export default class Count extends Component {

	state = {count:0}

	//加法
	increment = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		this.setState({count:count+value*1})
	}
	//减法
	decrement = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		this.setState({count:count-value*1})
	}
	//奇数再加
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		if(count % 2 !== 0){
			this.setState({count:count+value*1})
		}
	}
	//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		const {count} = this.state
		setTimeout(()=>{
			this.setState({count:count+value*1})
		},500)
	}

	render() {
		return (
			<div>
				<h1>当前求和为:{this.state.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
			</div>
		)
	}
}

redux 精简版

提出redux概念
  1. 先上图, 把流程先跑一边, 并和vuex做一个区别,有利于理解
    1)component组件作为吃饭客户, action作为服务员, store作为老板, reducers作为后厨。接着来跑一下流程 : 客户点了一份食品类型为 type :牛肉, data:3斤。 action作为服务员接受到这个信息并记录了一条订单返回一个对象 { type:“牛肉”, data :“3斤” }。并且通过dispatch(分发)订单给老板, 老板自然是不干活的, 就让后厨 reducers来进行处理,那么reducers是一个函数, 先会接收到两个参数当前的库存的值(previousState),以及传递过来的订单(action)。 reducers处理好数据后,返回最新的一个库存(state)的情况。并告诉给store。用户也可以直接获取到库存的数值。
    在这里插入图片描述
redux精简版代码

代码结构
在这里插入图片描述

  1. store
/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//暴露store
export default createStore(countReducer)
  1. 组件
  • 通过dispatch来驱动
  • 通过store.getState()来获取state的数据
import React, { Component } from 'react'
//引入store,用于获取redux中保存状态
import store from '../../redux/store'

export default class Count extends Component {

	state = {carName:'奔驰c63'}

	/* componentDidMount(){
		//检测redux中状态的变化,只要变化,就调用render
		store.subscribe(()=>{
			this.setState({})
		})
	} */

	//加法
	increment = ()=>{
		const {value} = this.selectNumber
		store.dispatch({type:'increment',data:value*1})
	}
	//减法
	decrement = ()=>{
		const {value} = this.selectNumber
		store.dispatch({type:'decrement',data:value*1})
	}
	//奇数再加
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		const count = store.getState()
		if(count % 2 !== 0){
			store.dispatch({type:'increment',data:value*1})
		}
	}
	//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		setTimeout(()=>{
			store.dispatch({type:'increment',data:value*1})
		},500)
	}

	render() {
		return (
			<div>
				<h1>当前求和为:{store.getState()}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
			</div>
		)
	}
}

  1. count_reducer
/* 
	1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
	2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/

const initState = 0 //初始化状态
export default function countReducer(preState=initState,action){
	// console.log(preState);
	//从action对象中获取:type、data
	const {type,data} = action
	//根据type决定如何加工数据
	switch (type) {
		case 'increment': //如果是加
			return preState + data
		case 'decrement': //若果是减
			return preState - data
		default:
			return preState
	}
}
  1. index.js
  • redux数据更新默认不能驱动视图更新, 因此需要设定redux中state数据发生更新后, 视图也能更新
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'

ReactDOM.render(<App/>,document.getElementById('root'))
// 订阅subscribe
store.subscribe(()=>{
	ReactDOM.render(<App/>,document.getElementById('root'))
})

逐渐完善板块

  1. 上面的精简版少了action步骤,那就加上把 ~
    在这里插入图片描述
    1) constants.js
/* 
	该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

2)count_action.js

  • 实际就是返回一个对象的函数
/* 
	该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

3)组件中

  • 实际就是将dispatch中的对象换成一个执行的函数
    在这里插入图片描述
  1. 处理下异步的事情吧?
  • 异步其实就是让action返回的是函数, 然后通过dispatch交给reducer来处理。
    1)action文件
/* 
	该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from './constant'

//同步action,就是指action的值为Object类型的一般对象
export const createIncrementAction = data => ({type:INCREMENT,data})
export const createDecrementAction = data => ({type:DECREMENT,data})

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const createIncrementAsyncAction = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(createIncrementAction(data))
		},time)
	}
}

2)组件

//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		// setTimeout(()=>{
			store.dispatch(createIncrementAsyncAction(value*1,500))
		// },500)
	}

3.)store.js

  • 想使用异步需要重新配置store文件,安装redux-thunk, 并结合 applyMiddleware,thunk 来用
/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'
//暴露store
export default createStore(countReducer,applyMiddleware(thunk))

react-redux基本概念

react-redux的使用可以大大提高开发效率。 但是存在这么一个情况:需要对上面的用法重新有一个新的概念 react-redux对组件提出了 容器组件和UI组件, 容器组件 : 操作redux的数据。并归类dispatch需要用到的方法,再将这些属性和方法传递给UI组件来使用。

在这里插入图片描述
1)容器组件

  • connect 用于连接容器组件和UI组件的一个渠道。有两个括号connect ()() 第一个括号接收两个形参,为两个函数。 第一个形参 :用于传递获取到的state中的数据, 第二个形参 : 用于传递含有dispatch的方法。 第二个括号用来传UI组件。
//引入Count的UI组件
import CountUI from '../../components/Count'
//引入action
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/count_action'

//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'

/* 
	1.mapStateToProps函数返回的是一个对象;
	2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
	3.mapStateToProps用于传递状态
*/
function mapStateToProps(state){
	return {count:state}
}

/* 
	1.mapDispatchToProps函数返回的是一个对象;
	2.返回的对象中的key就作为传递给UI组件props的key,value就作为传递给UI组件props的value
	3.mapDispatchToProps用于传递操作状态的方法
*/
function mapDispatchToProps(dispatch){
	return {
		jia:number => dispatch(createIncrementAction(number)),
		jian:number => dispatch(createDecrementAction(number)),
		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
	}
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

2)UI组件接收数据

import React, { Component } from 'react'

export default class Count extends Component {

	state = {carName:'奔驰c63'}

	//加法
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.jia(value*1)
	}
	//减法
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.jian(value*1)
	}
	//奇数再加
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.jia(value*1)
		}
	}
	//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.jiaAsync(value*1,500)
	}

	render() {
		//console.log('UI组件接收到的props是',this.props);
		return (
			<div>
				<h1>当前求和为:{this.props.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
			</div>
		)
	}
}

  1. 优化一下
    1)将UI组件合并到容器组件中
    在这里插入图片描述

在这里插入图片描述

2)将传递的两个形参简化一下

在这里插入图片描述
3)subcribe优化一下, 使用 Provider 来替代subcribe

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import store from './redux/store'
// 导入
import {Provider} from 'react-redux'

ReactDOM.render(
	<Provider store={store}>
		<App/>
	</Provider>,
	document.getElementById('root')
)

4)完整代码如下 :

import React, { Component } from 'react'
//引入action
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/count_action'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'

//定义UI组件
class Count extends Component {

	state = {carName:'奔驰c63'}

	//加法
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.jia(value*1)
	}
	//减法
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.jian(value*1)
	}
	//奇数再加
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.jia(value*1)
		}
	}
	//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.jiaAsync(value*1,500)
	}

	render() {
		//console.log('UI组件接收到的props是',this.props);
		return (
			<div>
				<h1>当前求和为:{this.props.count}</h1>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
			</div>
		)
	}
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(
	state => ({count:state}),

	//mapDispatchToProps的一般写法
	/* dispatch => ({
		jia:number => dispatch(createIncrementAction(number)),
		jian:number => dispatch(createDecrementAction(number)),
		jiaAsync:(number,time) => dispatch(createIncrementAsyncAction(number,time)),
	}) */

	//mapDispatchToProps的简写
	{
		jia:createIncrementAction,
		jian:createDecrementAction,
		jiaAsync:createIncrementAsyncAction,
	}
)(Count)

数据共享版本

在这里插入图片描述
1)store.js

/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/

//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware,combineReducers} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './reducers/count'
//引入为Count组件服务的reducer
import personReducer from './reducers/person'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//汇总所有的reducer变为一个总的reducer
const allReducer = combineReducers({
	he:countReducer,
	rens:personReducer
})

//暴露store
export default createStore(allReducer,applyMiddleware(thunk))

2)count-组件

  • 分批次获取在这里插入图片描述
import React, { Component } from 'react'
//引入action
import {
	createIncrementAction,
	createDecrementAction,
	createIncrementAsyncAction
} from '../../redux/actions/count'
//引入connect用于连接UI组件与redux
import {connect} from 'react-redux'

//定义UI组件
class Count extends Component {

	state = {carName:'奔驰c63'}

	//加法
	increment = ()=>{
		const {value} = this.selectNumber
		this.props.jia(value*1)
	}
	//减法
	decrement = ()=>{
		const {value} = this.selectNumber
		this.props.jian(value*1)
	}
	//奇数再加
	incrementIfOdd = ()=>{
		const {value} = this.selectNumber
		if(this.props.count % 2 !== 0){
			this.props.jia(value*1)
		}
	}
	//异步加
	incrementAsync = ()=>{
		const {value} = this.selectNumber
		this.props.jiaAsync(value*1,500)
	}

	render() {
		//console.log('UI组件接收到的props是',this.props);
		return (
			<div>
				<h2>我是Count组件,下方组件总人数为:{this.props.renshu}</h2>
				<h4>当前求和为:{this.props.count}</h4>
				<select ref={c => this.selectNumber = c}>
					<option value="1">1</option>
					<option value="2">2</option>
					<option value="3">3</option>
				</select>&nbsp;
				<button onClick={this.increment}>+</button>&nbsp;
				<button onClick={this.decrement}>-</button>&nbsp;
				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
			</div>
		)
	}
}

//使用connect()()创建并暴露一个Count的容器组件
export default connect(
	state => ({
		count:state.he,
		renshu:state.rens.length
	}),
	{
		jia:createIncrementAction,
		jian:createDecrementAction,
		jiaAsync:createIncrementAsyncAction,
	}
)(Count)


公司实际中的项目应用

1) 项目结构
在这里插入图片描述

  1. store: 定义store
import {applyMiddleware, createStore} from 'redux'
import reduxThunk from 'redux-thunk' //使store.dispatch()可以接受函数
import reducers from '../reducer'

const logger = store => next => action => {
	if(typeof action === 'function'){
		// console.log('dispatching a function')
	}else{
		console.log('dispatching a action: ' + action.type)
	}
	console.log('prevState', store.getState())
	const result = next(action)
	console.log('nextState', result)
	return result
}
const middlewares = [
	logger,
	reduxThunk
]

// 2.创建store
const store = createStore(reducers, applyMiddleware(...middlewares))
export default store

reducer-index.js

import {combineReducers} from 'redux'
import work from './work'
import files from './files'
import api from './api'
import common from './common'

const index = combineReducers({
	work: work,
	files: files,
	api: api,
	common: common
})

export default index

reducer-files-index.js

import Types from "../../action/types";

const defaultState = {
  files: [],
  preUploadFile: null,
  currFile: null,
  uploadAgainFile: null,
  successFileGuids: [],
  selectedFile: {}
};

export default function onAction(state = defaultState, action) {
  switch (action.type) {
    case Types.FILES_CHANGE:
      return {
        ...state,
        files: action.files,
      };
    case Types.PREUPLOADFILE_CHANGE:
      return {
        ...state,
        preUploadFile: action.preUploadFile,
      };
    case Types.CURRFILE_CHANGE:
      return {
        ...state,
        currFile: action.currFile,
      };
    case Types.UPLOADAGAINFILE_CHANGE:
      return {
        ...state,
        uploadAgainFile: action.uploadAgainFile,
      };
    case Types.SUCCESSFILEGUIDS_CHANGE:
      return {
        ...state,
        successFileGuids: action.successFileGuids,
      };
      case Types.SELECTEDFILE_CHANGE:
        return {
          ...state,
          selectedFile: action.selectedFile,
        };
    default:
      return state;
  }
}

action-type.js

export default {
  FILES_CHANGE: "FILES_CHANGE",
  WORK_CHANGE: "WORK_CHANGE",
  ADDMUSICAUDIOSTARTPLAYTIME_CHANGE: "ADDMUSICAUDIOSTARTPLAYTIME_CHANGE",
  ADDMUSICAUDIOVOLUMEOBJ_CHANGE: "ADDMUSICAUDIOVOLUMEOBJ_CHANGE",
  SUBTITLEWORKLIST_CHANGE: "SUBTITLEWORKLIST_CHANGE",
  QUICKLYPOSITION_CHANGE: "QUICKLYPOSITION_CHANGE",
  ADDWATERMARKWORKLIST_CHANGE: "ADDWATERMARKWORKLIST_CHANGE",
  FETCHABORT_CHANGE: "FETCHABORT_CHANGE",
  SUCCESSFILEGUIDS_CHANGE: "SUCCESSFILEGUIDS_CHANGE",
  SELECTEDFILE_CHANGE: "SELECTEDFILE_CHANGE",
};

action-index.js

import {
  onFilesChange,
  onPreUploadFileChange,
  onCurrFileChange,
  onUploadAgainFileChange,
  onSuccessFileGuidsChange,
  onSelectedFileChange,
} from "./files";
import { onFileListModalChange, onTokenIdChange, onHandleImgErrChange, onUserActionChange } from "./common";
import {
  onWorkChange,
  onPrevWorkChange,
  onCutWorkListChange,
  onResolutionChange,
  onVideoBgColorChange,
  onUploadingChange,
  onUploadPercentChange,
  onProcessPercentChange,
  onProcessStepChange,
  onMergeWorkListChange,
  onCurrProgressChange,
  onStartTimeChange,
  onCancelProgressChange,
  onPlaybackRateChange,
  onCropChange,
  onRotateChange,
  onFlipChange,
  onFillingChange,
  onRemoveWatermarkListChange,
  onDragVideoPositionChange,
  onFileToBlobStatusChange,
  onSubmittingChange,
  onUploadXHRChange,
  onAddMusicWorkObjChange,
  onAddMusicAudioStartPlayTimeChange,
  onAddMusicAudioTimeObjChange,
  onAddMusicAudioVolumeObjChange,
  onSubtitleWorkListChange,
  onAddWatermarkWorkListChange,
  onQuicklyPositionChange,
  onFetchAbortChange,
  onLoopTimesChange,
  onReverseObjChange,
  onProcessModalVisibleChange,
} from "./work";

export default {
  onFilesChange,
  onWorkChange,
  onPrevWorkChange,
  onCutWorkListChange,
  onMergeWorkListChange,
  onResolutionChange,
  onFileListModalChange,
  onProcessPercentChange,
  onVideoBgColorChange,
  onTokenIdChange,
  onPreUploadFileChange,
  onUploadingChange,
  onUploadPercentChange,
  onProcessStepChange,
  onHandleImgErrChange,
  onCurrProgressChange,
  onStartTimeChange,
  onCurrFileChange,
  onCancelProgressChange,
  onUserActionChange,
  onPlaybackRateChange,
  onCropChange,
  onRotateChange,
  onFlipChange,
  onFillingChange,
  onRemoveWatermarkListChange,
  onDragVideoPositionChange,
  onFileToBlobStatusChange,
  onSubmittingChange,
  onUploadAgainFileChange,
  onUploadXHRChange,
  onAddMusicWorkObjChange,
  onAddMusicAudioTimeObjChange,
  onAddMusicAudioStartPlayTimeChange,
  onAddMusicAudioVolumeObjChange,
  onSubtitleWorkListChange,
  onQuicklyPositionChange,
  onAddWatermarkWorkListChange,
  onFetchAbortChange,
  onSuccessFileGuidsChange,
  onSelectedFileChange,
  onLoopTimesChange,
  onReverseObjChange,
  onProcessModalVisibleChange,
};

action-file-index.js

import Types from "../types";

export function onFilesChange(files) {
  return { type: Types.FILES_CHANGE, files: files };
}

export function onPreUploadFileChange(preUploadFile) {
  return { type: Types.PREUPLOADFILE_CHANGE, preUploadFile: preUploadFile };
}

export function onCurrFileChange(currFile) {
  return { type: Types.CURRFILE_CHANGE, currFile: currFile };
}

export function onUploadAgainFileChange(uploadAgainFile) {
  return { type: Types.UPLOADAGAINFILE_CHANGE, uploadAgainFile: uploadAgainFile };
}

export function onSuccessFileGuidsChange(successFileGuids) {
  return { type: Types.SUCCESSFILEGUIDS_CHANGE, successFileGuids: successFileGuids };
}

export function onSelectedFileChange(selectedFile) {
  return { type: Types.SELECTEDFILE_CHANGE, selectedFile: selectedFile };
}

入口函数index.js部分代码

ReactDOM.render(
  <Provider store={store}>
    <App lang={lang} />
  </Provider>,
  document.getElementById("hitpaw-root")
);

组件中使用
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值