🔍 登录 注册

redux与redux-thunk的使用

大 大苹果 2018-05-20 linux 👁 671 ⏱ 8min

redux

  • redux是一个可预测的状态容器,(区别于Wordpress framework - Redux Framework)
  • 它可以帮助您编写在不同环境(客户端,服务器和本地)中运行一致并且易于测试的应用程序。 最重要的是,它提供了出色的开发者体验,例如结合时间旅行调试器进行实时代码编辑。
  • 你可以结合react一起使用redux。或者其他任何的视图库,redux很小,包括依赖仅仅2kb。
  • 安装
npm install --save redux
# 补充包
# 也许你还要和react一起使用,并且需要开发工具
npm install --save react-redux
npm install --save-dev redux-devtools
  • 例子
import { createStore } from 'redux'
 
/**
* 这是一个reducer,它是一个具有(state,action)=>状态签名的纯函数。
* 它描述了动作如何将状态转换为下一个状态。
* 状态的形状取决于你:它可以是一个基元,一个数组,一个对象,
* 甚至是Immutable.js数据结构。 唯一重要的部分是你应该
* 不改变状态对象,但如果状态改变则返回一个新的对象。
* 在这个例子中,我们使用`switch`语句和字符串,但是你可以使用一个帮助器
* 遵循不同的约定(如功能图),如果它适合你的项目。
 */
function counter(state = 0, action) {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}
 
// 创建一个持有应用状态的Redux store。
// 他的api { subscribe, dispatch, getState }.
let store = createStore(counter)
 
// 你可以通过subscribe()来更新ui来响应状态的改变。
// 通常你会使用视图绑定库 (比如:React-Redux) 比起直接用 subscribe() 。
// 但是,将当前状态保存在localStorage中也可能非常方便。
 
store.subscribe(() =>
  console.log(store.getState())
)
 
// 改变内部状态的唯一方法是发送一个action。
// 这些动作可以被序列化,记录或存储,并在以后重播。
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })

您不需要直接改变状态,而是使用称为操作的简单对象指定想要发生的突变。然后编写一个称为reducer的特殊函数来决定每个操作如何转换整个应用程序的状态。

如果您用过Flux,那么您需要了解一个重要的差异。 Redux没有分派器或支持许多store。相反,只有一个store具有单一根reducer函数。随着您的项目的扩展,您不必添加store,而是将根reducer分解为更小的reducer,并独立运行于状态树的不同部分。这就好像React应用程序中只有一个根组件,但它由许多小组件组成。

这种体系结构可能看起来像一个反应器应用程序的矫枉过正,但这种模式的美妙之处在于它如何适应大型复杂的应用程序。它还支持非常强大的开发者工具,因为可以追踪引发它的操作的每个变异。您可以记录用户会话并通过重播每一个动作来重现它们。

中间件redux-thunk

  • 用途
    redux thunk 中间件允许你写入一个action创建者通过返回一个函数来代替action。thunk通常被用于延迟一个action的分发。或分发一些条件可以预测的action。内部函数接收store方法dispatch和getState作为参数。一个thunk函数包含一个表达式来延迟他的计算。
    - 安装
npm install --save redux-thunk
  • 启用redux-thunk,使用applyMiddleware()
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
 
// Note: redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
  • 例子如下:
const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
 
function increment() {
  return {
    type: INCREMENT_COUNTER
  };
}
// 异步 
function incrementAsync() {
  return dispatch => {
    setTimeout(() => {
      // 用dispatch可以处理同步和异步的action
      dispatch(increment());
    }, 1000);
  };
}
// 一个action创建者返回一个函数去实现条件分发
function incrementIfOdd() {
  return (dispatch, getState) => {
    const { counter } = getState();
 
    if (counter % 2 === 0) {
      return;
    }
 
    dispatch(increment());
  };
}
  • 作用
    任何来自内部函数的返回值都将作为dispatch本身的返回值。 这对于编写一个异步控制流来说非常方便,因为thunk动作创建者相互调度并返回Promise以等待对方的完成:
  • 示例代码
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
 
// Note: redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
 
function fetchSecretSauce() {
  return fetch('https://www.google.com/search?q=secret+sauce');
}
 
// 正常action的创建
// 他们返回的action可以在没有任何中间件的情况下派发
// 然而他们只能表达事实,而不是异步流程。
 
function makeASandwich(forPerson, secretSauce) {
  return {
    type: 'MAKE_SANDWICH',
    forPerson,
    secretSauce
  };
}
 
function apologize(fromPerson, toPerson, error) {
  return {
    type: 'APOLOGIZE',
    fromPerson,
    toPerson,
    error
  };
}
 
function withdrawMoney(amount) {
  return {
    type: 'WITHDRAW',
    amount
  };
}
 
// 甚至没有中间件你可以分发action.
store.dispatch(withdrawMoney(100));
 
// 当你需要使用异步操作比如api的调用或路由转换
// thunk函数返回一个函数
function makeASandwichWithSecretSauce(forPerson) {
 
  // 反转控制
  // 返回一个接受`dispatch`的函数,以便稍后分发。
  // Thunk 中间件知道如何将异步action转换为action
  return function (dispatch) {
    return fetchSecretSauce().then(
      sauce => dispatch(makeASandwich(forPerson, sauce)),
      error => dispatch(apologize('The Sandwich Shop', forPerson, error))
    );
  };
}
 
// Thunk 中间件让我们分发thunk异步action
// 就好像自己的action一样
store.dispatch(
  makeASandwichWithSecretSauce('Me')
);
 
// 它甚至需要关心thunk的返回值
// 对于dispatch, 我们只有声明一个promise对象并返回他们.
 
store.dispatch(
  makeASandwichWithSecretSauce('My wife')
).then(() => {
  console.log('Done!');
});
 
// 事实上,我们通过编写dispacth的action。
// 来自其他action创建者创建的action和 异步actiuon,
// 我们可以通过promise构建控制流
 
function makeSandwichesForEverybody() {
  return function (dispatch, getState) {
    if (!getState().sandwiches.isShopOpen) {
 
      // 你不必返回promise对象,这是很便利的
      // 因此调用者可以始终使用.then()函数来获取异步分发的结果
      return Promise.resolve();
    }
 
    // 我们可以分发普通对象action和其他thunk,
    // 这使得我们可以在单个流程中组合异步操作
 
    return dispatch(
      makeASandwichWithSecretSauce('My Grandma')
    ).then(() =>
      Promise.all([
        dispatch(makeASandwichWithSecretSauce('Me')),
        dispatch(makeASandwichWithSecretSauce('My wife'))
      ])
    ).then(() =>
      dispatch(makeASandwichWithSecretSauce('Our kids'))
    ).then(() =>
      dispatch(getState().myMoney > 42 ?
        withdrawMoney(42) :
        apologize('Me', 'The Sandwich Shop')
      )
    );
  };
}
 
// 这对服务端渲染非常有用,因为我们可以等待服务器的响应。
// 知道服务端响应的数据完成然后才开始同步渲染应用。
store.dispatch(
  makeSandwichesForEverybody()
).then(() =>
  response.send(ReactDOMServer.renderToString())
);
 
//我们也可以在一个组件中分发一个异步的thunk action。
// 任何时间它的props的改变将加载缺少的数据
 
import { connect } from 'react-redux';
import { Component } from 'react';
 
class SandwichShop extends Component {
  componentDidMount() {
    this.props.dispatch(
      makeASandwichWithSecretSauce(this.props.forPerson)
    );
  }
 
  componentWillReceiveProps(nextProps) {
    if (nextProps.forPerson !== this.props.forPerson) {
      this.props.dispatch(
        makeASandwichWithSecretSauce(nextProps.forPerson)
      );
    }
  }
 
  render() {
    return 

{this.props.sandwiches.join('mustard')}

} } export default connect( state => ({ sandwiches: state.sandwiches }) )(SandwichShop);
  • 注入自定义参数
    自2.1.0以来,Redux Thunk支持使用withExtraArgument函数注入自定义参数:
const store = createStore(
  reducer,
  applyMiddleware(thunk.withExtraArgument(api))
)
 
// 然后
function fetchUser(id) {
  return (dispatch, getState, api) => {
    // 你可以在这里使用api
  }
}
  • 要传递多个东西,只需将它们包装在单个对象中并使用解构:
const store = createStore(
  reducer,
  applyMiddleware(thunk.withExtraArgument({ api, whatever }))
)
 
// 然后
function fetchUser(id) {
  return (dispatch, getState, { api, whatever }) => {
    // 你可以在这里使用api和其他东西
  }
}

读完了?给作者一点支持

本文采用 CC BY 4.0 协议转载 · © 大苹果

评论(0)

登录 后参与评论。

  • 还没有评论,来抢沙发。

🔗 相关文章

Mysql 表被标记为崩溃,最后一次自动化修复失败

当 MySQL 日志中出现“表被标记为崩溃且自动修复失败”的提示时,通常表示 MySQL 在启动过程中检测到某个表的文件系统或存储引擎层出现了问题。这种情况通常会导致表无法正常使用,需要手动进行修复。以下是处理这种情况的一些步骤和方法: ### 1. **查看具体错误信息** 首先,需要查看 MySQL 错误日志以获取更多的错误信息。这可以帮助确定崩溃的表和具体的问题。 ```bash # 查看 MySQL 错误日志 tail -f /var/log/mysql/error.log ``` ### 2. **修复表** 不同的存储引擎有不同的修复工具,以下是常用的修复方法: #### **使用 `myisamchk` 修复 MyISAM 表** 如果崩溃的表使用的是 MyISAM 存储引擎,可以使用 `myisamchk` 工具来修复表。 1. 停止 MySQL 服务: ```bash sudo systemctl stop mysql ``` 2. 使用 `myisamchk` 修复表:

2024/8/11👍 0

mermaid.min.js的使用及介绍

`mermaid.min.js` 是一个 JavaScript 库,用于在浏览器中轻松绘制复杂的图表和流程图。Mermaid 通过使用简单的标记语言来描述图表,使得用户无需深入学习图表绘制的底层技术即可创建专业的图形。 在这篇文章中,我们将介绍 `mermaid.min.js` 的功能、应用场景、如何在项目中使用,以及一些常用的示例。 ## Mermaid 的功能 Mermaid 支持多种类型的图表,包括但不限于: 1. **流程图(Flowchart)**: - 用于表示流程或过程中的步骤。 - 支持各种节点和连线风格。 2. **序列图(Sequence Diagram)**: - 用于表示对象之间的交互。 - 展示消息的发送和接收过程。 3. **类图(Class Diagram)**: - 用于表示类及其关系。 - 支持类的属性和方法定义。 4. **状态图(State Diagram)**: - 用于描述系统状态及其转换。 - 适用于复杂的状态机建模。 5. **甘

2024/8/9👍 0

docker之Dockerfile及docker compose配置文件的说明及使用

Docker 的配置文件对于镜像构建和容器化应用的管理至关重要。在 Docker 中,主要的配置文件是 Dockerfile 和 docker-compose.yml。Dockerfile 用于构建镜像,而 docker-compose.yml 用于定义多容器应用。下面将详细介绍这两个文件的配置选项和用法。 ## Dockerfile 配置详解 **Dockerfile** 是一个文本文件,其中包含一组指令,用于定义如何构建 Docker 镜像。以下是 Dockerfile 中常用的指令及其用法: ### FROM `FROM` 指令用于指定基础镜像,是 Dockerfile 中的第一条指令。 ```dockerfile FROM node:14 ``` 上例中,`node:14` 是官方的 Node.js 版本 14 的镜像。 ### LABEL `LABEL` 用于为镜像添加元数据,以键值对形式存在。 ```dockerfile LABEL maintainer="your-email@example.com" LABE

2024/8/9👍 0