redux应用笔记

项目中应用到了redux,根据前人的代码和网上百度到的资料总结如下,以免遗忘。

一图胜千言

简介

redux是一个状态管理工具,随着前端功能的增加,业务的复杂,将数据提取出组件是更好的方式,rudex是其中一种解决方案。

redux基本概念

redux由store、action、reducer 三部分组成。

store

store:仓库,是一个包括项目所有的状态数据的对象,redux提供了createStore函数来创建一个store

const store = createStore(reducer); //参数reducer下面介绍

action

action:动作,是一种包括类型和数据的对象,是reducer函数的参数,为reducer提供参数来进行不同的处理,典型形式是:

  {
    type:"ADD_CART_NUM",
    data: data
  }

reducer

reducer:处理函数(我的翻译),是一个具体的业务处理函数,位于action和disptch之间,被dispatch调用,根据传入action对象数据进行处理并返回一个新的state。典型形式是:

// 通过判断Action的类型,返回新的数据改变后的state对象,即使没有任何状态的改变,也要返回一个对象
// 注意:返回的state就是reducer提供的,也就是组件同步到的state
function counter(state = initState, action) { //state是reducer提供的默认值
  const count = state.count
  switch (action.type) {
    case ADD_CART_NUM:
      return { count: count + action.data.plusCount} //action.data是组件传入的的值
    default:
      return state
  }
}

dispatch

dispath: 分发函数(我的翻译),是store内部的函数,传入action并调用reducer,一般形式为:

<button onClick={()=>store.dispatch(myAction.increaseCartNum())}>Increase</button>
//其中increaseCartNum返回一个action对象,在dispath内部进行对应reducer的调用

subscribe

subscribe: 注册监听函数(我的翻译),也是store内部的函数,用于组件同步store中数据,一般形式为:

componentWillMount(){
  // 订阅状态变化
  store.subscribe((state)=>this.setState(state)) //注册到监听器函数到store中
}

问题 store中是如何区分不同组件的state呢?

redux流转流程

假设store中数据位于上层,组件位于下层,那么有数据上行和数据下行两种流转。

数据下行

store通过props传递到具体组件,组件通过this.props.xxx拿到数据。

数据上行

组件中点击按钮等操作调用store的dispatch函数(对应的action作为函数参数),dispatch函数内部调用相应的recuder函数,改变并返回store数据

react-reduce

在react应用中,利用react-redux来对两者进行桥接使用。
react提供了一个函数和一个组件,简化redux流程
connect函数:实现同步store数据到组件的props中、暴露action函数隐藏对dispatch调用reducer。一般形式为


// 绑定store中的状态到组件的props
const mapStateToProps = state => {
	return {
		state
	}
}

//暴露action到组件props
const mapDispatchToProps = dispath => {
	return bindActionCreators({
		changeCartNum
	}, dispath)
}

export default connect(mapStateToProps, mapDispatchToProps)(MiniCart) //其中MiniCart是组件

Provider标签用于将store传递到每个组件中,一般形式为:

ReactDOM.render(
  <Provider store={store} >
      <Router>
          <LocaleProvider locale={zh_CN}><App /></LocaleProvider>
      </Router>
  </Provider >
  , document.getElementById('root'));

整体代码

//action.js aciton文件
export function changeCartNum(data) {
    return {
        type: 'CART_NUM',
        data
    }
}


//frontReducer.js  子reducer文件,不同模块分为不同reducer文件

const init = { //reducer的初始状态

}
 
const Front = (state = init, action = {}) => {
  switch (action.type) {
    case 'CART_NUM':
      //这里可以添加一些处理函数,
      return { ...state, ...action.data }
  }
}
export default Front


//reducers.js 总reducers文件
import { combineReducers } from 'redux'

import Front from './FrontReducer';


const reducer = combineReducers({ //合并reducer文件
    Front,
    xxx,//不同的reducer文件
    xxx,//不同的reducer文件
})

export default reducer

//index.js文件

const store = createStore(reducer);
ReactDOM.render(
  <Provider store={store} > //传递store到内部组件中
      <Router>
          <LocaleProvider locale={zh_CN}><App /></LocaleProvider>
      </Router>
  </Provider >
  , document.getElementById('root'));

//B组件获取cartNumber

import { changeCartNum } from '@actions';
class PublicTop extends React.Component {
  render(){
    ....
    <span >
      购物车数量
      {
        this.props.state.Front.cartNum 
      }
    </span>
    .....
  }
}

const mapStateToProps = state => {
	return {
		state
	}
}

const mapDispatchToProps = dispath => {
	return bindActionCreators({
		changeCartNum
	}, dispath)
}

export default connect(mapStateToProps, mapDispatchToProps)(MiniCart)


//A组件设置cartNumber

import { changeCartNum } from '@actions'; // 购物车数量
class Cart extends Component {
  render(){
    .......
      //增加购物车数量按钮的点击处理函数
      this.props.changeCartNum({ cartNum: totals })//totals是设置的值
    .......
  }
}

const mapStateToProps = state => {
	return {
		state
	}
}

const mapDispatchToProps = dispath => {
	return bindActionCreators({
		changeCartNum
	}, dispath)
}

export default connect(mapStateToProps, mapDispatchToProps)(Cart)


redux原生操作

以下程序是没有使用react-redux的原生操作,包括store的简易实现,用于理解redux的实现。

//reducer文件 counterReducer.js

// 提供一个初始的状态
initState={
 count: 0 
}

// 通过判断Action的类型,返回新的数据改变后的state对象,即使没有任何状态的改变,也要返回一个对象
export default function counter(state = initState, action) {
  const count = state.count
  switch (action.type) {
    case INCREMENT:
      return { count: count + 1 }
    default:
      return state
  }
}

//主文件 index.js

// 创建一个store全局管理state和操作
const store = createStore(reducer); 

// Provider在根组件<App>外面包了一层,App的所有子组件就默认都可以拿到store,通过组件的props传递
export default class Root extends Component {
    render() {
        return (
            <Provider store={store}>
                <App/>
            </Provider>
        )
    }
}

// createStore的简单实现

function createStore = ( reducer ) => {
  let currentState; // 内部的状态
  let listeners = []; //所有的监听者
  
  const getState = () => currentState;  // 获取store中的state
  
  // dispatch的操作就是内部执行reducer()函数,action和reducer在这儿产生交集,并且通知所有的监听者
  const dispatch = ( action ) => {
    currentState = reducer(state, action); // 更新state
    listeners.forEach(listener => listener());
  }
  
  // 订阅事件
  const subscribe = ( listener ) => {
    listeners.push(listener);
    return ()=>{
      listeners = listeners.filter(l => l !== listener)
    }
  }

  return {
    getState,
    dispatch,
    subscribe
  }
}



//组件文件
class Counter extends Component{

  componentWillMount(){
    // 订阅状态变化
    store.subscribe((state)=>this.setState(state)) //注册到监听器函数到store中
  }

  render() {
    return (
      <div>
        <span>{value}</span>
        //点击后dispatch事件类型
        <button onClick={()=>store.dispatch(increaseAction.increase())}>Increase</button>
      </div>
    )
  }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章