程序员让前端飞前端开发笔记

redux入门

2018-11-07  本文已影响20人  yonglei_shang

什么是redux


Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

什么时候使用redux


如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

基础和概念


state

当使用普通对象来描述应用的 state 时:

{
  loginName: '',
  visibilityFilter: 'SHOW_COMPLETED'
}

这个对象就像 “Model”,区别是它并没有 setter(修改器方法)。因此其它的代码不能随意修改它,造成难以复现的 bug。

action

Action 就是一个普通 JavaScript 对象,像这样:

{type: 'SET_NAME', text: 'tom'},
{type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL'}

强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。

注:

在redux中约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。多数情况下,type 会被定义成字符串常量。当应用规模越来越大时,建议使用单独的模块或文件来存放 action。

reducer

把 action 和 state 串起来,开发一些函数,这就是 reducer。

reducer 只是一个接收 state 和 action,并返回新的 state 的函数。

function loginName(state = '', action) {
  if (action.type === 'SET_NAME') {
    return action.filter;
  } else {
    return state;
  }
}

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    return state;
  }
}

再开发一个 reducer 调用这两个 reducer,进而来管理整个应用的 state:

function reducers(state = {}, action) {
  return {
    loginName: loginName(state.loginName, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  };
}

注:

reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

每个 reducer 只负责管理全局 state 中它负责的一部分。每个 reducer 的 state 参数都不同,分别对应它管理的那部分 state 数据。

这差不多就是 Redux 思想的全部。redux 就是提供一些简单的工具来简化这种模式。

redux 三大原则


redux API


createStore(reducer, [preloadedState], enhancer)

创建一个 Redux store来以存放应用中所有的 state。

应用中应有且仅有一个 store。

参数

返回值

Store: 保存了应用所有 state 的对象。

Store

Store 就是用来维持应用所有的state 树 的一个对象。

Store 不是类。它只是有几个方法的对象。 要创建它,只需要把根部的 reducing 函数 传递给 createStore

Store 方法 介绍 参数 返回值
getState() 得到state -- (any): 应用当前的 state 树。
dispatch 分发 action。这是触发 state 变化的惟一途径。 action (Object) (Object): 要 dispatch 的 action。
subscribe 一个变化监听器。每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。 listener (Function): 每当 dispatch action 的时候都会执行的回调。state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。 (Function): 一个可以解绑变化监听器的函数。
replaceReducer(nextReducer) 替换 store 当前用来计算 state 的 reducer。这是一个高级 API。只有在你需要实现代码分隔,而且需要立即加载一些 reducer 的时候才可能会用到它。 reducer (Function) store 会使用的下一个 reducer。 ---

combineReducers(reducers)

combineReducers 辅助函数的作用是,把一个由多个不同 reducer 函数作为 value 的 object,合并成一个最终的 reducer 函数。

合并后的 reducer 可以调用各个子 reducer,并把它们返回的结果合并成一个 state 对象。由 combineReducers() 返回的 state 对象,会将传入的每个 reducer 返回的 state 按其传递给 combineReducers() 时对应的 key 进行命名。

rootReducer = combineReducers({potato: potatoReducer, tomato: tomatoReducer})
// rootReducer 将返回如下的 state 对象
{
  potato: {
    // ... potatoes, 和一些其他由 potatoReducer 管理的 state 对象 ... 
  },
  tomato: {
    // ... tomatoes, 和一些其他由 tomatoReducer 管理的 state 对象,比如说 sauce 属性 ...
  }
}

参数

reducers (Object): 一个对象,它的值(value)对应不同的 reducer 函数,这些 reducer 函数后面会被合并成一个。

返回值

(Function):一个调用 reducers 对象里所有 reducer 的 reducer,并且构造一个与 reducers 对象结构相同的 state 对象。

注:

每个传入 combineReducers 的 reducer 都需满足以下规则:

示例

//reducers/todos.js
export default function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    return state.concat([action.text])
  default:
    return state
  }
}
//reducers/counter.js
export default function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}
//reducers/index.js
import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'

export default combineReducers({
  todos,
  counter
})
//App.js
import { createStore } from 'redux'
import reducer from './reducers/index'

let store = createStore(reducer)
console.log(store.getState())
// {
//   counter: 0,
//   todos: []
// }

store.dispatch({
  type: 'ADD_TODO',
  text: 'Use Redux'
})
console.log(store.getState())
// {
//   counter: 0,
//   todos: [ 'Use Redux' ]
// }

applyMiddleware(...middlewares)

使用包含自定义功能的 middleware 来扩展 Redux 是一种推荐的方式。Middleware 可以让你包装 store 的 dispatch 方法来达到你想要的目的。

参数

使用

import { applyMiddleware, createStore, compose } from 'redux'
import reducers from './reducers'
import {createLogger} from 'redux-logger'
import middlePromise from 'redux-promise'
// import thunk from 'redux-thunk'

// 模拟 logger
const logger = store => next => action =>{
  console.log('prev state',store.getState())
  console.log('dispatch',action);

  let result = next(action);

  console.log('next state',store.getState());

  return result;
}

const  store = createStore(reducers, applyMiddleware(middlePromise, logger))

export default store

// 异步
import { applyMiddleware, createStore, compose } from 'redux'
import reducers from './reducers'
import {createLogger} from 'redux-logger'
// import middlePromise from 'redux-promise'
import thunk from 'redux-thunk'

// 模拟 logger
const logger = store => next => action =>{
  console.log('prev state',store.getState())
  console.log('dispatch',action);
  let result = next(action);

  console.log('next state',store.getState());

  return new Promise((resolve, reject) => {
    resolve(result)
  });
}

const  store = createStore(reducers, compose(applyMiddleware(thunk, logger)))

export default store

注:

bindActionCreators(actionCreators, dispatch)

把一个 value 为不同 action creator 的对象,转成拥有同名 key 的对象。同时使用 dispatch对每个 action creator 进行包装,以便可以直接调用它们。

参数

  1. actionCreators (Function or Object): 一个 action creator,或者一个 value 是 action creator 的对象。

  2. dispatch (Function): 一个由 Store实例提供的 dispatch函数。

返回值

(Function or Object): 一个与原对象类似的对象,只不过这个对象的 value 都是会直接 dispatch 原 action creator 返回的结果的函数。如果传入一个单独的函数作为 actionCreators,那么返回的结果也是一个单独的函数。

示例在react-redux中讲解

compose(...functions)

从右到左来组合多个函数。

当需要把多个store 增强器 依次执行的时候,需要用到它。

参数

(arguments): 需要合成的多个函数。预计每个函数都接收一个参数。它的返回值将作为一个参数提供给它左边的函数,以此类推。例外是最右边的参数可以接受多个参数,因为它将为由此产生的函数提供签名。(compose(funcA, funcB, funcC) 形象为 compose(funcA(funcB(funcC()))))

返回值

(Function): 从右到左把接收到的函数合成后的最终函数。

react-redux 基本使用


React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)。

UI 组件有以下几个特征。

示例

const Title = props => <h1>{props.title}</h1>;

容器组件

React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成。

connect()

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

示例

import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(Title)

connect方法接受两个参数:mapStateToPropsmapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action。

connect参数 介绍 参数
mapStateToProps mapStateToProps是一个函数。它的作用就是像它的名字那样,建立一个从(外部的)state对象到(UI 组件的)props对象的映射关系。 第一个永远是state;第二个参数ownProps:代表容器组件的props对象
mapDispatchToProps 用来建立 UI 组件的参数到store.dispatch方法的映射 dispatchownProps(容器组件的props对象)两个参数

示例

const mapStateToProps = (state, ownProps) => {
 return {
   state: state,
   title: state.increment + ownProps.title
 }
}
const mapDispatchToProps = (dispatch, ownProps) => {
 return {
   actions: bindActionCreators(actionCreators, dispatch),
   ownPropsClick: () => {
     dispatch(actionCreators.increment())
     console.log(ownProps.title)
   }
 }
}

// mapDispatchToProps 也可以是一个对象
// const mapDispatchToProps = {
//   ownPropsClick: (filter) => {
//     return {
//       type: 'INCREMENT',
//       filter: filter
//     }
//   }
// }

export default connect(mapStateToProps, mapDispatchToProps)(Test)

<Provider store>

<Provider store> 使组件层级中的 connect() 方法都能够获得 Redux store。正常情况下,你的根组件应该嵌套在 <Provider> 中才能使用 connect() 方法。

属性

示例

ReactDOM.render(
  <Provider store={store}>
    <App/>
  </Provider>,
  rootEl
)

redux的使用先讲到这里,如有错误之处希望大家积极留言!

上一篇下一篇

猜你喜欢

热点阅读