React 實踐項目 (二)

来源:http://www.cnblogs.com/yuicon/archive/2017/07/09/7141050.html
-Advertisement-
Play Games

React在Github上已經有接近70000的 star 數了,是目前最熱門的前端框架。而我學習React也有一段時間了,現在就開始用 React+Redux 進行實戰! React 實踐項目 (一)本次實踐代碼 部署好的網址 上回說到用React寫了一個帶Header的首頁,我們這次實踐就使用R ...


React在Github上已經有接近70000的 star 數了,是目前最熱門的前端框架。而我學習React也有一段時間了,現在就開始用 React+Redux 進行實戰!

React 實踐項目 (一)

本次實踐代碼

部署好的網址

上回說到用React寫了一個帶Header的首頁,我們這次實踐就使用Redux進行狀態管理

index

Rudex

應用中所有的 state 都以一個對象樹的形式儲存在一個單一的 store 中。
惟一改變 state 的辦法是觸發 action,一個描述發生什麼的對象。
為了描述 action 如何改變 state 樹,你需要編寫 reducers。

我們接下來開始開始進行登陸與註冊的狀態管理

首先在 src 目錄下創建 redux 文件夾,目錄如下

digag
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   └── favicon.ico
│   └── index.html
│   └── manifest.json
└── src
    └── components
        └── Index
            └── Header.js
            └── LoginDialog.js
            └── RegisterDialog.js
    └── containers
        └── App
            └── App.js
            └── App.css
    └── redux
        └── action
            └── users.js
        └── reducer
            └── auth.js
            └── users.js
        └── sagas
            └── api.js
            └── sagas.js
            └── selectors.js.js
            └── users.js
        └── store
            └── store.js
    └── App.test.js
    └── index.css
    └── index.js
    └── logo.svg
    └── registerServiceWorker.js

代碼可從此獲取

記得在 package.json 中更新依賴

接下來我會開始解釋關鍵代碼

  • action
    action/users.js
/*
 * action 類型
 */
export const REGISTER_USER = 'REGISTER_USER';
// 省略其他action 類型

/*
 * action 創建函數
 */
export const registerAction = (newUser) => {
  return{
    type:REGISTER_USER,
    data: newUser,
  }
};
// 省略其他 action 創建函數
  • reducer
    reducer/users.js
//Immutable Data 就是一旦創建,就不能再被更改的數據。
//對 Immutable 對象的任何修改或添加刪除操作都會返回一個新的 Immutable 對象。
import Immutable from 'immutable';
//從 action 導入需要的 action 類型
import {REGISTER_USER, REGISTER_USER_SUCCESS, REGISTER_USER_FAILURE} from '../action/users';

// 初始化狀態
const initialState = Immutable.fromJS({
  newUser: null,
  error: null,
  saveSuccess: false,
});

//  reducer 就是一個純函數,接收舊的 state 和 action,返回新的 state。
export const users = (state = initialState, action = {}) => {
  switch (action.type) { // 判斷 action 類型
    case REGISTER_USER:  
      return state.merge({   // 更新狀態
        'newUser': action.data,
        'saveSuccess': false,
        'error': null,
      });
    case REGISTER_USER_SUCCESS:
      return state.set('saveSuccess', action.data);
    case REGISTER_USER_FAILURE:
      return state.set('error', action.data);
    default:
      return state
  }
};
  • store
    store/store.js
import {createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga'
import * as reducer from '../reducer/users';

import rootSaga from '../sagas/sagas';

const sagaMiddleware = createSagaMiddleware();

const store = createStore(
  combineReducers(reducer),
  applyMiddleware(sagaMiddleware)
);

sagaMiddleware.run(rootSaga);

export default store;

然後在入口文件使用 store

src/index.js

import {Provider} from 'react-redux';
import store from './redux/store/store';
// 省略其他

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

在 App.js 中獲取 action 和 狀態

import {registerAction, loginAction} from '../../redux/action/users';
import {connect} from "react-redux";
import {bindActionCreators} from "redux";
 //省略其他

class App extends Component {

  render(){
    return(
      <div className="App">
        //省略
      </div>
    )
  }

}

export default connect(
  (state) => {
// 獲取狀態   state.users  是指 reducer/users.js 文件中導出的 users
// 可以 `console.log(state);` 查看狀態樹
  return { users: state.users }
},
  (dispatch) => {
  return {
// 創建action
    registerActions: bindActionCreators(registerAction, dispatch),
    loginActions: bindActionCreators(loginAction, dispatch),
  }
})(App);
// 在App 組件的props里就有 this.props.users  this.props.registerActions this.props.loginActions 了
// 需要註意的是這裡this.props.users是Immutable 對象,取值需要用this.props.users.get('newUser') 
// 也可在 reducer 里改用 js 普通對象

裝飾器版本:
需要在Babel中開啟裝飾器
裝飾器插件babel-plugin-transform-decorators-legacy

@connect(
  (state) => {
    console.log(state);
    return ({
      users: state.users,
    });
  },
  {registerActions: registerAction, loginActions: loginAction}
)

最後把 registerActions 傳給RegisterDialog子組件,

src/components/Index/RegisterDialog.js

// 省略其他代碼
 handleSubmit = (e) => {
    e.preventDefault();
    // 驗證表單數據
    this.refs.user.validate((valid) => {
      if (valid) {
        // this.state.user 為表單收集的 用戶註冊數據
        this.props.registerActions(this.state.user);
        this.setState({loading: true});
      }
    });
  };

流程是:

  • 調用 action
    this.props.registerActions(this.state.user);
    返回action 為
{
    type:REGISTER_USER,
    data: this.state.user,
}
  • reducer 根據action類型更新狀態
switch (action.type) {
    case REGISTER_USER:
      return state.merge({
        'newUser': action.data,
        'saveSuccess': false,
        'error': null,
      });
//省略其他代碼

這時我們的store里的狀態 newUser就被更新為 註冊彈窗里收集的數據
到這裡都還是同步的action,而註冊是一個非同步的操作。
下篇文章會介紹如何使用 redux-saga 進行非同步操作。
redux-saga 已經在使用了,有興趣的可以自行查看代碼理解。

記得點star:)
項目代碼地址:https://github.com/DigAg/digag-pc-react
vue2版項目代碼地址:https://github.com/DigAg/digag-pc-vue2
相應後端項目代碼地址:https://github.com/DigAg/digag-server


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

-Advertisement-
Play Games
更多相關文章
  • 這是我的第一遍博文,我來試試感覺 ...
  • 1.正則表達式 js 中判斷某個元素是否存在於某個 js 數組中,相當於 PHP 語言中的 in_array 函數。 Array.prototype.in_array=function(e){ var r=new RegExp(','+e+','); return (r.test(','+this. ...
  • 1.xhtml和html有什麼區別 HTML是一種基本的WEB網頁設計語言,XHTML是一個基於XML的置標語言 最主要的不同: XHTML 元素必須被正確地嵌套。 XHTML 元素必須被關閉。 標簽名必須用小寫字母。 XHTML 文檔必須擁有根元素 2、簡述一下src與href的區別: href ...
  • 如果你是一個人在自學前端開發,或者是對前端開發有比較濃厚的興趣正想踏入前端領域,只要你在前端自學路上遇到了自己無法解決的技術難題,那麼儘管將你的疑惑交給我的小伙伴兒們吧,我們都是一群在前端自學路上摸爬滾打的有志青年,希望你可以來和我們共同交流。同時也希望你能獻出自己的一份力,幫助我的小伙伴兒們解決他 ...
  • 上一篇的gulp配置很簡單,主要就是為了demo的查看和調試,這一篇則會相對詳細一些,包括壓縮合併打時間戳等。 在互聯網環境比較好的城市,需要多人協作的,大一點的項目應該都用上了模塊化(這裡主要指commonjs和ES6模塊系統,不是再早的require.js和sea.js)。代碼也會更註重如何分離 ...
  • 摘要: 前端框架 Bootstrap 的模態對話框,可以使用 remote 選項指定一個 URL,這樣對話框在第一次彈出的時候就會自動從這個地址載入數據到 .modal-body 中,但是它只會載入一次,不過通過在事件中調用 removeData() 方法可以解決這個問題。 1. Bootstrap ...
  • 1、對於string,number等基礎類型,==和 是有區別的 1)不同類型間比較,==之比較“轉化成同一類型後的值”看“值”是否相等, 如果類型不同,其結果就是不等 2)同類型比較,直接進行“值”比較,兩者結果一樣 2、對於Array,Object等高級類型,==和 是沒有區別的 進行“指針地址 ...
  • 上次分享完該系列文章後有朋友也建議說1.x版本除了維護也沒有必要學習,可以學習2.0開始學習,我也知道1.x無論是從性能還是架構上都沒有2.x好,但是我想因為現在也有一些朋友還在用1.x版本,因為1.x升級到2.x難度很大,甚至可以說重構,就向我們公司現在還在用1.x版本,所以我還是決定把這系列寫完 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...