redux

来源:https://www.cnblogs.com/guolao/archive/2019/03/21/10571605.html
-Advertisement-
Play Games

redux 記錄一下 redux 的一些用法,如果想學習 redux,建議看 "官方文檔" ,另外推薦一本 "huzidaha" 寫的 "react小書" ,裡面講解了一些 react 和 redux 的原理。 start 運行如下命令,不瞭解 npx 的,可以看一下 "阮一峰的文章" 。 然後安裝 ...


redux

記錄一下 redux 的一些用法,如果想學習 redux,建議看官方文檔,另外推薦一本huzidaha寫的react小書,裡面講解了一些 react 和 redux 的原理。

start


運行如下命令,不瞭解 npx 的,可以看一下阮一峰的文章

// 腳手架創建項目
npx create-react-app redux-test
// 進入文件夾
cd redux-test
// 啟動 react
npm run start

然後安裝 redux:

npm i -S redux react-redux

接著把 src 下的文件都刪掉幾個,只剩兩個文件:

src/
|--index.js
|--serviceWorker.js

redux and react-redux


打開上面留下的 index.js,刪掉裡面的代碼,敲下自己的代碼,然後刷新網頁。

// index.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import * as serviceWorker from './serviceWorker'
import { createStore } from 'redux'
import { connect, Provider  } from 'react-redux'

// actionTypes
const NUM_ADD = 'NUM_ADD';

// actionCreator
function addNum () {
  return {
    type: NUM_ADD
  }
}

// reducer
const initialState = {
  num: 0
}

function counter (state = initialState, action) {
  switch  (action.type) {
    case NUM_ADD:
      return {
        num: state.num + 1
      }
    default:
      return state
  }
}

// store
const store = createStore(counter)

// App
class App extends Component {
  render() {
    return (
      <div>
        {this.props.num}
        <button onClick={this.props.onClickAdd}>add</button>
      </div>
    );
  }
}

// connect(mapStateToProps, mapDispatchToProps)(component)
const mapStateToProps = state => {
  return {
    num: state.num
  }
}

const mapDispatchToProps = dispatch => {
  return {
    onClickAdd: () => {
      dispatch(addNum())
    }
  }
}

App = connect(mapStateToProps, mapDispatchToProps)(App)

// Provider 傳入 store
ReactDOM.render(
<Provider store={store}>
  <App />
</Provider>, document.getElementById('root'));

serviceWorker.unregister();

mapDispatchToProps


connect中的mapDispatchToProps可以是一個函數,也可以是一個對象,函數寫法如上。

mapDispatchToProps是一個對象時,redux 會把它裡面的屬性作為actionCreator交給dispatch使用,簡單來說,就是 redux 幫你把對象裡面的屬性封裝為函數型的mapDispatchToProps,寫法如下:

// index.js
...
// App
class App extends Component {
  render() {
    return (
      <div>
        {this.props.num}
        // 這裡也進行了修改 
        // onClickAdd -> addNum
        <button onClick={this.props.addNum}>add</button>
      </div>
    );
  }
}
...
// connect
App = connect( 
  state => state, 
  { addNum }
)(App)
...

@connect


connect可以使用裝飾器的寫法。

// 裝飾器的 babel 插件
npm i -S @babel/plugin-proposal-decorators

然後進行配置 plugin,這裡有兩種配置方法:

  1. 使用 create-react-app 的配置

    // 暴露配置
    npm run eject
    // 會進行確認
    Are you sure you want to eject? This action is permanent.(y/n) y

    然後會看到文件夾內多了一些東西,打開項目根路徑下的 package.json 文件,找到 babel 配置項:

    // package.json
    ...
    "babel": {
        "presets": [
          "react-app"
        ],
        "plugins": ["@babel/plugin-proposal-decorators", { "legacy": true }]
      },
    ...
  2. 使用獨立文件配置 babel:

    打開項目根路徑下的 package.json 文件,找到 babel 配置項,將他刪掉:

    // package.json
    ...
    // 把這個刪掉
    "babel": {
        "presets": [
          "react-app"
        ],
      },
    ...

    然後在項目根目錄創建.babelrc文件。

    // .babelrc
    {
      "presets": ["react-app"],
      "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true }]
    }

配置完 babel 之後,打開 src 下的 index.js 進行修改:

// index.js
...
// App
// 裝飾器寫法
@connect(
  state => state, 
  { addNum }
)
class App extends Component {
  render() {
    return (
      <div>
        {this.props.num}
        <button onClick={this.props.addNum}>add</button>
      </div>
    );
  }
}
...

註意:對於裝飾器的支持只是實驗性的,未來可能會改動。

redux-thunk


可以使用中間件 redux-thunk 進行非同步操作,它可以讓actionCreator不返回action對象,而是返回一個函數,可以在函數內封裝邏輯。

function incrementIfOdd() {
  // 接收兩個參數
  // getState() 可以拿到 store 中的 state
  return (dispatch, getState) => {
    const { counter } = getState();
    if (counter % 2 === 0) {
      return;
    }
    dispatch(increment());
  };
}

首先還是安裝:

npm i -S redux-thunk

然後打開 index.js 進行修改:

// index.js
...
import {createStore, applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
...
// store
const store = createStore(counter, applyMiddleware(thunk))
...

非同步操作有很多,這裡將 num 的增加推遲為 1s 後才進行:

// index.js
// actionCreator
function addNum () {
  return {
    type: NUM_ADD
  }
}

function addNumAsync () {
  return dispatch => {
    setTimeout(() => {
      dispatch({type: NUM_ADD})
    }, 1000)
  }
}

// App
@connect(
  state => state, 
  { addNum, addNumAsync }
)
class App extends Component {
  render() {
    return (
      <div>
        {this.props.num}
        <button onClick={this.props.addNum}>add</button>
        <button onClick={this.props.addNumAsync}>add after 1s</button>
      </div>
    );
  }
}

combineReducers


當你有多個 reducer 時,可以使用combineReducers,進行合併。

import { createStore, combineReducers } from 'redux'

const allReducer = combineReducers({
  reducerOne,
  reducersTwo
})

store = createStore(allReducer)

bindActionCreators


把 actionCreator 傳到一個子組件中,卻不想讓這個組件覺察到 Redux 的存在,而且不希望把 dispatch 或 store 傳給它時,可以使用bindActionCreators

這裡使用官方文檔的例子:

// TodoActionCreators.js
export function addTodo(text) {
  return {
    type: 'ADD_TODO',
    text
  };
}

export function removeTodo(id) {
  return {
    type: 'REMOVE_TODO',
    id
  };
}
// SomeComponent.js
import { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';

import * as TodoActionCreators from './TodoActionCreators';
console.log(TodoActionCreators);
// {
//   addTodo: Function,
//   removeTodo: Function
// }

class TodoListContainer extends Component {
  constructor(props) { 
    super(props);

    const {dispatch} = props;

    // 這是一個很好的 bindActionCreators 的使用示例:
    // 你想讓你的子組件完全不感知 Redux 的存在。
    // 我們在這裡對 action creator 綁定 dispatch 方法,
    // 以便稍後將其傳給子組件。

    this.boundActionCreators = bindActionCreators(TodoActionCreators, dispatch);
    console.log(this.boundActionCreators);
    // {
    //   addTodo: Function,
    //   removeTodo: Function
    // }
  }

  componentDidMount() {
    // 由 react-redux 註入的 dispatch:
    let { dispatch } = this.props;

    // 註意:這樣是行不通的:
    // TodoActionCreators.addTodo('Use Redux')

    // 你只是調用了創建 action 的方法。
    // 你必須要同時 dispatch action。

    // 這樣做是可行的:
    let action = TodoActionCreators.addTodo('Use Redux');
    dispatch(action);
  }

  render() {
    // 由 react-redux 註入的 todos:
    let { todos } = this.props;

    return <TodoList todos={todos} {...this.boundActionCreators} />;

    // 另一替代 bindActionCreators 的做法是
    // 直接把 dispatch 函數當作 prop 傳遞給子組件,但這時你的子組件需要
    // 引入 action creator 並且感知它們

    // return <TodoList todos={todos} dispatch={dispatch} />;
  }
}

export default connect(state => ({ todos: state.todos }))(TodoListContainer)

備註


個人學習 redux 的感受,看,不如動手去敲。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...