redux学习记录

redux 虽然以re开头,但其实并不是react官方提供的库。这并不妨碍它成为热门的redux解决方案
所有的状态都保存在一个对象中(store),view视图与状态是一一对应的

如果你不知道是否需要用redux,那你就不需要redux
只有遇到 react 实在解决不了的问题,你才需要 redux

在这里插入图片描述

API:

1. Store

用来保存数据,整个应用只能有一个 Store。通过Redux提供的createStore函数来生成Store。
createStore函数接受另一个函数作为参数,返回新生成的 Store 对象。

import { createStore } from 'redux';
const store = createStore(reducer);

Store共提供了三个方法 getState()、dispatch()、subscribe()

let { subscribe, dispatch, getState } = createStore(reducer);

createStore方法还可以接受第二个参数,表示 State 的最初状态。通常是接口的返回。

2. State

从Store中取出的某一时刻的数据。可以使用store.getState()来取得

import { createStore } from 'redux';
const store = createStore(reducer);

const state = store.getState()
3. Action

用户通过View层的操作来改变Store中的数据,Action 就是 View 发出的通知。它会运送数据到 Store。表示State要变化了

const action = {
  type: 'test', // 必须
  payload: {}
};
4. Reducer

创建Store的时候提到过,createStore函数接受另一个函数作为参数,这个参数就是Reducer。它接受 Action 和当前 State 作为参数,返回一个新的 State。表示会对state如何进行修改。

const reducer = (state, action) => {
  switch (action.type) {
    case 'ADD':
      return state + action.payload;
    default: 
      return state;
  }
};

const state = reducer(1, {
  type: 'ADD',
  payload: 2
});

Reducer是一个纯函数,其接受同样的输入,必定得到同样的输出。因此它必须满足:

  • 不能修改参数
  • 不能使用I/O
  • 不能使用获取时间戳Date.now()或者随机数Math.random()等方法。

实际开发中可以将 reducer 拆分为多个子 ‘reducer’ 在传递给store之前通过combineReducers()方法合并成一个reducer

5. dispatch()

store.dispatch()是 View 发出 Action 的唯一方法。它接受一个Action对象作为参数。该方法在发送Action的时候会自动调用Reducer并执行,因此,需要在store创建的时候传入Reducer函数。

import { createStore } from 'redux';
const store = createStore(reducer);

store.dispatch({
  type: 'test', 
  payload: {}
});
6. subscribe()

store.subscribe()方法可以设置监听函数,用于监听State的变化。

import { createStore } from 'redux';
const store = createStore(reducer);

store.subscribe(listener);

一旦State发生变化,listener函数就会执行。如果将Redux的setState方法放入listener中,就可以将State变化与View关联起来,触发页面更新。
如果想要解除监听,可以调用这个方法的返回函数

let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
);

unsubscribe();
简单实现store
const createStore = (reducer) => {
  let state;
  let listeners = [];

  const getState = () => state; // 返回当前state

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());//state变化了,遍历执行所有listener中的函数
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      listeners = listeners.filter(l => l !== listener);//取消监听时,从所有listener中剔除该listener
    }
  };

  dispatch({});

  return { getState, dispatch, subscribe };
};

React-Redux

为了方便在React项目中使用Redux,React的作者封装了一个库,就是React-Redux。实际项目中,你应该权衡一下,是直接使用 Redux,还是使用 React-Redux。后者虽然提供了便利,但是需要掌握额外的 API,并且要遵守它的组件拆分规范。

React-Redux 将所有组件分成两类:UI 组件(presentational component)和容器组件(container component)
UI 组件:顾名思义,就是不带有业务逻辑,仅作为展示用的组件。内部数据都由this.props来提供。
容器组件:与UI组件相对的就是容器组件,它负责管理数据和业务逻辑。

1. connect()
React-Redux 提供connect方法,用于从 UI 组件生成容器组件

  //TodoList是 UI 组件,ContentTodoList就是由 React-Redux 通过connect方法生成的容器组件。
 import { connect } from 'react-redux'
const ContentTodoList = connect()(TodoList);

为了实现UI组件与容器组件之间的交互,就需要:①将state数据传递给UI组件。②把UI组件中用户的操作转化为Action传递到容器组件中。
为此,connect方法会接受mapStateToProps和mapDispatchToProps两个函数来分别做这两件事。
2. mapStateToProps()
用来建立state到UI组件的映射关系,接收State作为参数,执行后返回一个对象,其中的每一个键值对就是一个映射。

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

上述例子中的key值todos表示是刚刚定义的TodoList UI组件所对应的数据,getVisibleTodos()是一个函数,可以根据State来算出TodoList组件的数据值。例如

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + filter)
  }
}

mapStateToProps会订阅Store,当State发生变化的时候,会自动触发,通过修改UI组件对应的数据参数,从而触发UI组件的重新渲染。
其实mapStateToProps还可以传入第二个参数,就是容器组件的Props,传入就会绑定容器组件的props,如果发生容器组件的参数改变,也会导致UI组件重新渲染。

3.mapDispatchToProps()
是connect的第二个参数,用来建立UI组件的参数到store.dispatch方法的映射(定义了哪些操作会被当做Action来传递给Store)可以是函数或对象

const mapDispatchToProps = {
  onClick: (filter) => {
    type: 'Add_Todo',
    filter: filter
  };
}

4. Provider
通过connect创建的容器组件,需要能够拿到State对象进行操作,才可以生成UI组件需要的参数。
如果通过props一层层传递会比较麻烦,于是React-Redux 提供Provider组件,可以让容器组件拿到state。

import { Provider } from 'react-redux'
import { createStore } from 'redux'
import todoApp from './reducers'
import App from './components/App'

let store = createStore(todoApp);

render(
//直接在跟组件<APP />外面包裹<Provider>,这样所有子组件都可以拿到State
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值