使用 Redux

简单使用

import { createStore } from "redux";

// 1. 新建 store
// 通过reducer建立
// 根据老的 state 和 action 生成新的 state
function counter(state = 0, action) {
  switch (action.type) {
    case "加机关枪":
      return state + 1;
    case "减机关枪":
      return state - 1;
    default:
      return 10;
  }
}

// 新建 store
const store = createStore(counter);

const init = store.getState();
console.log(init);

store.dispatch({ type: "加机关枪" });
console.log(store.getState());
store.dispatch({ type: "加机关枪" });
console.log(store.getState());
store.dispatch({ type: "减机关枪" });
console.log(store.getState());

优化

App.js

import React from "react";

class App extends React.Component {
  // constructor(props) {
  //   super(props)
  // }
  render() {
    const store = this.props.store;
    const num = store.getState();
    const addGun = this.props.addGun;
    const removeGun = this.props.removeGun;
    return (
      <div>
        <h1>
          现在有机枪
          {num}把
        </h1>
        <button onClick={() => store.dispatch(addGun())}>申请武器</button>
        <button onClick={() => store.dispatch(removeGun())}>上交武器</button>
      </div>
    );
  }
}

export default App;

index.js

import React from "react";
import ReactDom from "react-dom";
import { createStore } from "redux";
import App from "./App";
import { counter, addGun, removeGun } from "./index.redux";

const store = createStore(counter);

function render() {
  ReactDom.render(
    <App store={store} addGun={addGun} removeGun={removeGun} />,
    document.getElementById("root")
  );
}
render();

store.subscribe(render);

index.redux.js

const ADD_GUN = "加机关枪";
const REMOVE_GUN = "减机关枪";

// reducer
export function counter(state = 0, action) {
  switch (action.type) {
    case ADD_GUN:
      return state + 1;
    case REMOVE_GUN:
      return state - 1;
    default:
      return 10;
  }
}

// action creator
export function addGun() {
  return { type: ADD_GUN };
}

export function removeGun() {
  return { type: REMOVE_GUN };
}

更进一步, 让 Redux 可以处理异步

  • Redux 处理异步, 需要 redux-thunk 插件
  • npm i redux-devtools-extension 开启
  • 使用 react-redux 优雅链接 react 和 redux

Redux 默认只处理同步, 异步任务需要 react-thunk 中间件

  • npm i redux-thunk
  • 使用 applyMiddleware 开启 thunk 中间件
  • Action 可以返回函数, 使用 dispatch 提交 action

App.js

  render() {
    const store = this.props.store
    const num = store.getState()
    const addGun = this.props.addGun
    const removeGun = this.props.removeGun
    const addGunAsync = this.props.addGunAsync
    return (
      <div>
        <h1>现在有机枪{num}把</h1>
        <button onClick={() => store.dispatch(addGun())}>申请武器</button>
        <button onClick={() => store.dispatch(removeGun())}>上交武器</button>
        <button onClick={() => store.dispatch(addGunAsync())}>拖两天再给</button>
      </div>
    )
  }

index.js

import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { counter, addGun, removeGun, addGunAsync } from "./index.redux";

const store = createStore(counter, applyMiddleware(thunk));

function render() {
  ReactDom.render(
    <App
      store={store}
      addGun={addGun}
      removeGun={removeGun}
      addGunAsync={addGunAsync}
    />,
    document.getElementById("root")
  );
}

index.redux.js

export function addGunAsync() {
  return dispatch => {
    setTimeout(() => {
      dispatch(() => {
        dispatch(addGun());
      });
    }, 2000);
  };
}

调试工具

  • Chrome 搜索 redux 安装
    • 新建 store 的时候判断 window.devToolsExtension
    • 使用 compose 结合 thunk 和 window.devToolsExtension
    • 调试窗的 redux 选项卡, 实时看到 state
// index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import App from "./App";
import { counter, addGun, removeGun, addGunAsync } from "./index.redux";

const store = createStore(
  counter,
  compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : () => {}
  )
);

使用 React-redux

  • npm i react-redux
  • 忘记 subscribe, 记住 reducer, action 和 dispatch 即可
  • React-redux 提供 Provider 和 connect 连个接口来链接

React-redux 具体使用

  • Provider 组件在应用最外层, 传入 store 即可, 只用一次
  • Connect 负责从外部获取组件需要的参数
  • Connect 可以用装饰器的方式来写
// index.js
import React from "react";
import ReactDom from "react-dom";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import { Provider } from "react-redux";
import App from "./App";
import { counter } from "./index.redux";

const store = createStore(
  counter,
  compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : () => {}
  )
);

ReactDom.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
// App.js
import React from "react";
import { connect } from "react-redux";
import { addGun, removeGun, addGunAsync } from "./index.redux";

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>
          现在有机枪
          {this.props.num}把
        </h1>
        <button onClick={this.props.addGun}>申请武器</button>
        <button onClick={this.props.removeGun}>上交武器</button>
        <button onClick={this.props.addGunAsync}>拖两天再给</button>
      </div>
    );
  }
}
const mapStatetoProps = state => {
  return { num: state };
};
const actionCreators = { addGun, removeGun, addGunAsync };

App = connect(
  mapStatetoProps,
  actionCreators
)(App);
export default App;

使用装饰器优化 Connect 代码

  • npm i -D babel-plugin-transform-decorators-legacy 安装插件
  • package.json 里 babel 加上 plugins 配置
"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": ["babel-plugin-transform-decorators-legacy"]
  }
// App.js
import React from "react";
import { connect } from "react-redux";
import { addGun, removeGun, addGunAsync } from "./index.redux";

@connect(
  state => ({ num: state }),
  { addGun, removeGun, addGunAsync }
)
class App extends React.Component {
  render() {
    const num = this.props.num;
    const addGun = this.props.addGun;
    const removeGun = this.props.removeGun;
    const addGunAsync = this.props.addGunAsync;
    return (
      <div>
        <h1>
          现在有机枪
          {num}把
        </h1>
        <button onClick={addGun}>申请武器</button>
        <button onClick={removeGun}>上交武器</button>
        <button onClick={addGunAsync}>拖两天再给</button>
      </div>
    );
  }
}

export default App;

验证属性

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容