主頁 > 前端設計 > redux 及 react-redux的詳細使用程序和案例 。分享搬磚知識的一天,期間打瞌睡了幾次。啊哈哈~

redux 及 react-redux的詳細使用程序和案例 。分享搬磚知識的一天,期間打瞌睡了幾次。啊哈哈~

2021-09-20 12:10:40 前端設計

搬磚搬磚,分享點搬磚技巧,
第六章了,差不多結束了 ,還有些零零散散的,慢慢搬吧,
之前的章節內容可點這~

第六章 — redux

redux中文官網

6.1 什么是 redux

官方是這樣子說的 :reduxJavaScript 應用程式可預測狀態容器 ,它可以幫助您撰寫行為一致、在不同環境(客戶端、服務器和本機)中運行且易于測驗的應用程式,

官方的解釋有時候總是看不懂的

說一下我的理解,

JavaScript 應用程式 : redux 和 react 可是兩回事,只是長的像而已, redux 可以在任何應用程式使用,

redux 有一個核心的東西 ,就是 store . 那現在有了一個新的問題,什么是 store ,

store 英文的釋義是商店,在 redux 里它是一個存盤資料的地方,就相當于一個容器,一個倉庫,整個程式只有一個 store這便于狀態的集中管理,

為什么說是可預測呢?

因為 redux 管理的資料的修改程序是我們設定的,也就是我們已經告訴他應該怎么做,并且每次修改之前是會接收到之前的狀態,程序是可預測,可跟蹤的,

6.2 為什么需要 redux

當程式的功能比較復雜,組件較多,并且需要共享狀態共享狀態困難時, 使用redux 是一個較好的解決方案,

我們可以通過這兩張圖理解:有 A , B ,C ,D, 四個房子(組件) ,它們總是會相互借東西,相互交流,(組件互動,狀態共享,修改資料),那么以我們之前的方法,像通過共同的父組件來傳遞資料,那么父組件會變得很臃腫,因為需要定義一些它本身不需要的狀態和方法,只是為了方便兒子們交流,

或者使用訊息訂閱-發布機制, B 需要 A的某個資料,就需要訂閱,然后 A 發布 ,然后 D也需要,于是 D 也需要訂閱,個組件來來往往就像如圖一樣亂七八糟,

在這里插入圖片描述

而使用 redux . 就相當于建了一個倉庫 , 各房子把需要共享的東西放在倉庫,誰需要誰去拿,那么不但把資料需要共享的資源統一一個地方存盤,并且方便了其他組件去使用,

在這里插入圖片描述

非必要,不使用 redux

并不是如何程式或者 使用了 react 就需要使用 redux 的 ,

有句話這樣子說

“如果你不知道是否需要 Redux,那就是不需要它,”

為什么呢 , redux 是便于組件共享狀態的,如果組件組件互動少,需要共享的狀態不多,且不需要 redux 便能解決的那么根本就不需要使用 redux ,

使用場景

  • 組件間需要共享狀態,互動較多
  • 不同身份的用戶有不同的使用方式(比如普通用戶和管理員)
  • 多個用戶之間可以協作
  • 與服務器大量互動,或者使用了WebSocket
  • View要從多個來源獲取資料

6.3redux 的作業流程圖解

在介紹如何使用之前,先了解一下redux 的作業流程是很有必要的,這有助于理解,
在這里插入圖片描述

Component 便是組件了

ActionCreators redux 分為 3個部分,核心部分是 Store , 然后是 ActionCreators 和 Reducers.

其中ActionCreators 是創建 action 的 ,也就是創建行為的一個模塊,

Reducers 處理 dispatch 發出的行為 ,也就是實際做出行動的模塊,

Store 便是保存狀態的核心部分 無論是發出行為,存盤資料,還是把結果反應出去都是通過它,

我們可以理解為 redux 就是一個飯店 ,各組件是客人,客人通過 服務員 ( ActionCreators) 下單 ,告訴需要什么菜,于是服務員跟老板說了(Store) , 然后老板讓廚師(Reducers) 做菜,最后客人從老板這兒了拿菜,這當然與實際有些不同,但這不妨礙我們更好理解這個程序,

回到實際, 組件在需要發出行為時,呼叫了 store上的 dispatch 方法 ,途中向 ActionCreators 拿了一下 action,并作為 dispatch 的引數傳給 store , 也就是實際上呼叫 dispatch方法 的是 組件,

然后Store 把 當前的狀態的 action 傳給 reducer , reducer 處理完后回傳新的 狀態 給 store,組件再通過 store 的 getState() 方法拿到新的狀態資料,

6.4 redux 的使用

安裝及基礎準備

通過 npm

npm install redux

通過 yarn

yarn add redux

創建相關檔案夾和檔案

創建組件和 redux 檔案夾及 redux 內相關檔案(如圖所示)

在這里插入圖片描述

因為 不同組件有不同的行為,因此可以把不同的 創建action 的檔案放在一個檔案夾里,如圖中的 actions檔案夾,

同理 不同組件發出行為的操作也不同 ,也需要不同的 reducer , 因此放在同一個檔案夾下,

而 store 僅有一個,因此直接放于 redux檔案夾下即可,

constant.js 檔案, 用于存盤 type 常量,因為 type 的值是我們事先給定的,通過不同 type 觸發不同的操作,因此在組件和 reducer 里都需要使用到 type 的值,使用常量,是便于修改,放在打錯字,

基本使用

假設我們需要完成一個例子
在這里插入圖片描述

將結果的資料存放在 state 中 , 點擊 + 或 - 可以對資料進行加一或者減一,結果默認顯示 99 ,

action

創建 action 的檔案不需要引入什么 API ,我們需要創建相關方法,該方法回傳通過 action

action 是一個物件, 包括兩個屬性 typedata , 分別是型別和資料, type 會表明到時候 reducer 應該執行的操作, data 是傳遞的資料,此資料來源組件,也就是 action 檔案暴露的方法是給組件呼叫的,并且組件會傳入一個資料,

// 分別暴露 創建的相應的創建 action 的方法 ,當其他地方需要使用action時,呼叫這個方法便創建并可以回傳 action,
export let createIncrease = (data) => ({ type: “increase”, data })   
export let createDecrease = (data) => ({ type: ”decrease“, data })
reducer

reducer檔案 也是不需要引入什么 API 的,它用來創建為某組件專門服務的 reducer 函式僅一個,判斷 type 提供不同的操作,

reducer 函式接收兩個引數 , 第一個是 preState , 其實是當前的狀態(因為經過此次操作后,會回傳新的 State ,因此把它叫做 preState, 含義是之前的狀態),第二個引數是 action ,

reducer 會在 redux 加載后執行一次,此次會回傳一個默認值,

/*
 1. 此檔案用來創建一個為 Count 組件的 服務的 reducer . 本質是一個函式
 2. 函式接收兩個引數 , 第一個是之前的 preState , 第二個是動作物件 action (包括行為,和資料)
*/
export default function countReducer(preState, action) {
    console.log(preState);
    console.log(action);
    const { type, data } = action
    switch (type) {
        case "increase":
            return preState + data
        case "decrease":
            return preState - data
        default:
            return 99  // 初始回傳的默認值
    }
}

注意:

  • preState 如果是原始值可以修改本身,再回傳本身,如果是參考值切記不能修改本身然后回傳本身 因為 redux 會對回傳值與 preState 進行地址比較,如果是一樣的地址會導致更新的失敗,
// 如果是原始值,如此操作不影響結果
case "increase" :  
	preState += data 
	return preState

// 如果是參考值 ,以下操作是錯誤的
case "pop" :{
    preState.pop()
    return preState
}
  • reducer 要求必須是一個純函式,但如果不存并不會報錯,存函式需要滿足以下幾點操作
1. 不得修改引數 (即使是原陣列,也盡量不要修改)
2. 不應該具有其他副功能,如果發送網路請求,連接到其他輸入輸出設備
3. 不能使用不存的函式,如 Date.now() , Math.random() 等回傳值不確定不唯一的 API,
store

store檔案 是 redux 的核心,

創建 store 需要從 redux 引入 createStore API , 它是一個函式,此函式回傳一個 Store,

createStore 函式可以接收三個引數,

第一個引數是 reducer(必須) , 或者是 reducers (多個 reducer 的合并,接下來會講),

第二個引數是 初始狀態(非必須) , 如果這個引數沒有給,那么第三個引數就成為了第二個引數,

第三個參是 支持異步 action 用的( 非必須,接下來會講) ,如果沒有第二引數,那么這個引數是第二引數,

import { createStore } from 'redux'

// 引入為 Count 專門服務的 reducer
import CountReducer from './reducers/count'
// 暴露 state
export default createStore(CountReducer)

如此 redux 的創建和基本代碼便完成了

接下來學習 store 的幾個 API 和使用 store

store.dispatch(action)

這是發出 action 的唯一方法 , 組件拿到action , 拿到 store . 便可呼叫 dispatch 方法,傳遞 action 給 store

/**  Count Component  **/

// 匯入 store
import store from '../../redux/store'
// 匯入創建 action 的函式
import { createIncrease } from '../../redux/actions/count' 

	// 組件實體的方法
    incread = () => {
        store.dispatch(
            createIncrease(1)
        )
    }
    
// 當 action 比較少時, 我們也可以不需要 action函式 ,
        store.dispatch(
            {
                type:"increase",
                data:1
            }
        )
store.getState()

store.getState() 是獲取 store 當前資料的一個 API ,也就是獲取 reducer 最后一次的回傳值,

// 匯入 store
import store from '../../redux/store'

// 組件內
render(){
    return (<h1>結果為 :{store.getState()}</h1>)   // 結果為 : 99
}
store.subscribe()

我們知道當組件的 state 改變時,會重新渲染組件 , 但無論是 store 還是 reducer 都不會把改完后的資料主動給組件,或者告訴組件一個更新了,因此 store 提供了 subscribe API , 當 store 重繪時,會執行這個 subscribe 函式 , 呼叫傳給 subscribe 的回呼函式,

因此利用這個API ,我們可以在 store 改變時,重繪 組件即可

/** scr/index.js  **/

import React from "react";
import ReactDOM from "react-dom";
import App from './App';
// 匯入 stre
import store from './redux/store'

ReactDOM.render(< App />, document.querySelector("#root"));

// 當 store 重繪時,重新渲染組件,便重新呼叫 getState 從而獲取新的狀態,
store.subscribe(() => {
    ReactDOM.render(< App />, document.querySelector("#root"));
})
// 如此全部組件都可以獲取新的 store 資料了
完成例子 - 加減計算器

redux 相關檔案和代碼在上面的介紹中已經完成,接下來我們看看完整的組件代碼,注意 scr/index.js內需要使用 subscribe API

import React, { Component } from 'react'
// 匯入 store
import store from '../../redux/store'
// 匯入 action
import { createIncrease, createDecrease } from '../../redux/actions/count'

export default class Count extends Component {
    incread = () => {
        store.dispatch( createIncrease(1))
    }
    decread = () => {
        store.dispatch(createDecrease( 1))
    }
    
    render() {
        return (
            <div>
                {/* 顯示結果 */}
                <h1>結果為 :{store.getState()}</h1>&nbsp;
                {/* 點擊加一 */}
                <button className="btn btn-default" onClick={this.incread} >+</button>&nbsp;&nbsp;
                {/* 點擊減一 */}
                <button className="btn btn-default" onClick={this.decread} >-</button>
            </div >
        )
    }
}

資料共享

在這里插入圖片描述

redux 的主要目的就是多狀態資料共享,所以這個功能是很重要的,

在前面的基本使用我們只創建一個了 reducer, 然后把該 reducer 作為 createStore() 的第一個引數 ,那如果我們使用 redux 幾乎不會只有一個 reducer 的,那么多個reducer 又怎么集合到一個 store 里,組件并且如何獲取資料呢?這就是接下來要討論的問題,

combineReducers

這是 redux 暴露的一個 API ,它用來把所有的 reducer 集合一起回傳值然后作為第一引數傳給 createStore (), 那么不同組件的 資料就可以集中保存到 store 中,需要就可以向 store 拿便可

// 額外匯入 combineReducers
import { createStore ,combineReducers} from 'redux'


// 引入 Count 的 reducer
import CountR from './reducers/countR'

// 引入 其他 reducer
import OtherR from './reducers/otherR'

// 呼叫 combineReducers ,傳入物件,回傳作為 createStore的第一個引數
const allReducer = combineReducers({
    data1:CountR,   // 為方便解釋,實際可不能這么順便
    data2:OtherR
})
// 創建store
export default createStore(allReducer)

除了增加一個 reducer 外,其他代碼并不需要修改上面(同基本使用一樣)

然后便是如何獲取資料了

雖然 store 保存了多個狀態了,但獲取資料還是通過 store.getState() 來獲取,

當只有一個 reducer 時store.getState() 的回傳值就是 該 reducer 處理完后 return 的 newState

當有多個 reducer 時 , store.getState() 回傳的是一個物件 ,可以理解為就是傳給 combineReducers的物件,不過鍵對于的值是每次執行對應的 reducer 后的回傳值 ,

// 如果 combineReducers 的引數是如此的

// const allReducer = combineReducers({
//    data1:CountR,   // 為方便解釋,實際可不能這么順便
//    data2:OtherR
// })

// 在組件里獲取相應 reducer 回傳的狀態就是
store.getState().key
// 如 獲取 Count 的 reducer 回傳的狀態
store.getState().data1

異步 action

在上面的例子中, action 都是同步的,也就是點擊加一后結果立即加一,如果有一個異步操作,比方說發個請求,或者倒計時幾秒后再執行應該怎么如何操作呢?

假設我們有這樣的一個需求,我們希望以上例子的基礎上加一個按鈕,點擊后3 秒再增1.

在這里插入圖片描述

如果把異步操作放在 視圖容器可就是組件里,那么異步加確實是很方便操作,

Asyncdecread = () => {
        setTimeout(() => {
        store.dispatch(
            createIncrease(1)
        )
    }, 3000);
}

但是我們是希望 組件是顯示狀態的 , 如果這種異步操作少,那么確實把異步放組件里很方便,也容易修改,

但一旦異步操作多了起來,資料處理更復雜了,那么組件就不該承當這些功能了,

Store 當然也不能做到異步操作, reducer 是純函式,只執行 State 的修改,那么實作異步 action 的任務還是歸給了 action Creators

applyMiddleware

我嘗試了在 action 里直接寫異步操作

setTimeout(() => {
    return { type: "increase", 1 }
}, 3000);

點擊加一后執行結果報錯, 報錯資訊說 action Creators 回傳的應該一個是一個物件,而不是 undefined

為什么呢?不是 3 秒后回傳 一個物件了嗎? 這就跟 JavaScript 的異步函式執行機制有關了,這說下去篇幅就大了,

總之呢就是不行,

為了實作異步 action , 我們需要 使用一個 東西, 叫 applyMiddleware

applyMiddleware 是一個函式 , 它可以對 store.dispatch() 進行改造 , 讓我們在執行 dispatch() 之后并且 在執行 reducer 之前能夠執行其他操作,如異步操作,

applyMiddleware 是 redux 提供了一個 API , 可作為 createStore()的 第二或 第三 個引數傳入 ,

export default createStore(reducer, applyMiddleware())

我們知道 action Creators 如果執行異步操作后再回傳 action 是無法被 store.dispatch 接收的 , 因此我們可以把思路轉到,執行異步操作后再執行 dispatch()

applyMiddleware 便支持我們這樣做 ,

// 組件
store.dispatch(createIncreaseaAsync(1, 3000))   // 表示 3 秒后加一

// action Creator 
export let createIncreaseaAsync = (data, delay) => {
    return (dispatch) => {
        setTimeout(() => {
            dispatch({type:"increase",data:data})
        }, delay);
    }
}

這里我們直接回傳一個函式,在函式內部執行異步操作,結束后再次發送 dispatch , 而這個 dispacth方法等同于 store.dispatch方法 , 它是 applyMiddleware 傳進來的 ,

如此我們便解決了異步的問題了 ,但這又有一個問題,就是 action Creators 要求回傳的是物件,可不是函式,

因此我們需要使用 一個 中間件 ,叫 redux-thunk

redux-thunk

redux-thunk 是一種中間件 , 它可以讓 action Creators 回傳函式,并且讓 dispatch() 可以接受函式引數,

中間件 - middleware , 它的使用方法就是作為 applyMiddleware 的引數,

使用程序

  • 安裝

yarn add redux-thunk

或者

npm install redux-thunk

  • 匯入

import thunk from ‘redux-thunk’

  • 使用

export default createStore(allReducer, applyMiddleware(thunk))

如此我們便可順利執行 異步 action 了 ,

異步action 實作代碼

store.js

// 額外匯入 applyMiddleware
import { createStore, applyMiddleware} from 'redux'
// 匯入 thunk
import thunk from 'redux-thunk';
// 引入 Count 的 reducer
import reducer from './reducers/count'

export default createStore(reducer, applyMiddleware(thunk))

action Creators

// 暴露創建action 加 減 的方法 
export let createIncrease = (data) => ({ type: 'increase', data })
export let createDecrease = (data) => ({ type: 'decrease', data })

// 匯出異步的 actiob.
export let createIncreaseaAsync = (data, delay) => {  // 接收兩個引數,資料和計時器倒計時長
    // 回傳函式
    return (dispatch) => {  // 函式接收到一個 dispatch 方法
        setTimeout(() => {
            dispatch(createIncrease(data))  // 異步操作結束后 重新 dispatch 發生 action 
        }, delay); 
    }
}

reducer

參考 redux 的基本使用 的 reducer 部分代碼,

Count-component 注意 要使用 store.subscribe() 在改變狀態時重新渲染組件

import React, { Component } from 'react'
// 匯入 store
import store from '../../redux/store'
// 匯入 action 和異步 action 
import { createIncrease, createDecrease, createIncreaseaAsync} from '../../redux/actions/count'

export default class Count extends Component {
    incread = () => {
        store.dispatch( createIncrease(1))
    }
    decread = () => {
        store.dispatch(createDecrease(1))
    }
    // 異步 action 
    increadAsync= ()=>{
        store.dispatch(createDecrease(1,3000))
    }
    render() {
        return (
            <div>
                {/* 顯示結果 */}
                <h1>結果為 :{store.getState()}</h1>&nbsp;
                {/* 點擊加一 */}
                <button className="btn btn-default" onClick={this.incread} >+</button>&nbsp;&nbsp;
                {/* 點擊減一 */}
                <button className="btn btn-default" onClick={this.decread} >-</button>&nbsp;&nbsp;
                {/* 點擊異步加一 */}
                <button className="btn btn-default" onClick={this.increadAsync} >異步執行</button>
            </div >
        )
    }
}

6.5 react-redux

react-redux 便是 react 官方出的了 , 它的作用是讓 react 使用 redux 更加方便 ,

但并不是必須要使用,因為需要學習成本,本身代碼量也可能會增加,并且有新的使用規則,

為什么使用 react-redux

  • 它區分了 UI 組件和 容器組件,進一步區別開邏輯和 UI ,
  • 它提供的效率,減少不必要的重新渲染,部分未更新的 State 不會導致 組件的重新渲染,
  • 它自動監聽 state 變化,自動重繪組件 ,

react-redux 作業原理圖

在使用前我們還是先看看它的 作業原理圖,便于接下來的學習,

在這里插入圖片描述

在之前 , redux 和 組件是直接聯系的 , 組件需要資料直接 store.getState() 也就是直接 store.dispatch()

react-redux 把組件分成了 容器組件UI 組件 , redux 的書寫無需更改,

容器組件把 UI 組件需要的 狀態和 創建 action 的函式 通過 props 傳遞給 UI 組件 , UI 組件負責顯示和 執行 函式修改狀態 , 但 UI 組件不會 引入 store 和 創建action的方法 , 這些邏輯的實作全都有 容器組件負責

說白了 UI 組件就是 給資料我顯示 ,給方法我執行 , 什么怎么來 , 方法的具體實作我都不管,

這里具體看看 兩個組件的要求 :

UI組件
  • 只負責 UI 的呈現,不帶有任何業務邏輯
  • 狀態和操作狀態的方法由容器組件提供
  • 不使用任何 Redux 的 API
容器組件
  • 負責管理資料和業務邏輯,不負責 UI 的呈現
  • 帶有內部狀態
  • 使用 Redux 的 API

具體實作

安裝

yarn add react-redux

或者

npm install react-redux

創建組件

因為 react-redux 把組件分為了 容器組件和 UI 組件 ,因此我們可以分為兩個檔案,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-poVXItUl-1631970048324)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210918181024805.png)]

connect

connect() 是 react-redux 暴露的一個 API , 它用來連接 容器組件和 UI 組件的 ,

此方法需要傳遞兩個函式引數 ,并且都是必須引數

第一個引數

mapStateToProps : 字面意思是映射狀態到 Props . 它是一個函式,此函式把需要的狀態資料取出 ,最后回傳一個物件 , 此物件里的鍵值會被傳遞到 UI 組件的 props屬性 里

此函式會接收到一個引數 , 此引數的資料相當于 store.getState() 回傳的資料,

function mapStateToProps(state){  // 由 react-redux 呼叫,會傳入引數 state . 即reducer處理后的狀態
    return {
        count:state   //  count 會被傳到 UI 組件的 props 里
    }
}

第二個引數

mapDispatchToProps : 意思是 映射 dispatch 到 props , 它是一個函式 , 此函式回傳一個物件,物件的鍵對應的值是一個函式,此函式執行的是 dispatch 方法,dispatch 是由 react-redux 傳進來的引數 ,

function mapDispatchToProps(dispatch){   // 傳入引數 dispatch
    return {
        fun1:(data)=>{dispatch(createIncrease(data))},  // 此方法會傳入到 UI 組件的 Props 里
        fun2:(data)=>{dispatch(createDecrease(data))},
    }
}

因此函式傳給 UI 組件,組件呼叫函式就相當于呼叫 dispatch了 ,

簡寫

  • 當需要的狀態不多,時我們可以把 mapStateToProps 以匿名箭頭函式的方式直接作為 connect 的引數,

  • 第二個引數可以直接是一個物件 , 重復的呼叫 dispatch 可不符合 react-redux 的目的, 因此我們只需要把鍵對應的值換成 action Creator , 然后 react-redux 會處理好,等組件呼叫時就相當于呼叫 dsipacth 了 ,

connect(
    state => ({ count: state}),
    {
        fun1: createIncrease   // 引數是正常接收的 , UI 組件呼叫 fun1(data) , 此引數會傳給 createIncrease函式,
        fun2: createDecrease
    }
 )

connect 回傳值

connect 回傳一個函式,實際上來說 , 這個回傳的函式才是真正創建 容器組件的函式 ,

是的,容器組件可不是我們自己寫的 ,而是 react-redux 創建的 ,

connect 回傳值的函式接收一個引數 ,此引數是 UI 組件 , 最后的回傳值才是容器組件 ,

// 引入 UI 組件
import CountUI from '../../component/Count'  // 會在下面的貼出代碼
// 獲取 創建 容器組件的函式
let containerCreator = connect(mapStateToProps,mapDispatchToProps)
// 創建容器組件
export default containerCreator(CountUI)  // 暴露容器組件

// 簡寫
export default connect(mapStateToProps,mapDispatchToProps)(CountUI)

容器組件創建好了,就該使用了

在 容器組件中我們沒有匯入 store , store 需要我們在使用容器組件時傳給容器組件的 props ,并且鍵就叫 store.

import React, { Component } from 'react'
// 匯入容器組件
import Count from './container/Count'
// 匯入 store
import store from './redux/store'

export default class App extends Component {
  render() {
    return (
      <div>
        <Count store={store} />
      </div >
    )
  }
}

因為容器組件的子組件是 UI 組件,因此我們只需要把 容器組件渲染出去, UI 組件自然就顯示出來了 ,

Provider

Provider 是 react-redux 暴露的一個組件 ,此組件沒有什么其他功能,也不負責渲染 UI , 它只做一件事,就是把 store 傳給所有的容器組件 , 從而不需要我們使用一個容器組件就自己手動傳一次 store ,

一般我們在 scr 下的入口檔案 即 index.js 檔案里使用 , 如此可以覆寫使用的 容器組件,

import React from "react";
import ReactDOM from "react-dom";
import App from './App';

// 匯入 store
import store from './redux/store'

// 匯入入 react-redux 提供 Provider 組件
import { Provider } from 'react-redux'

ReactDOM.render(
<Provider store={store} >
    < App />
</Provider>, 
document.querySelector("#root"));

如果還記得之前的 store.subscribe() 就會發現, 這里我們沒有使用它了,因為 react-redux 會幫我們監聽 store 里狀態的改變 ,并且自動更新,

具體代碼

container/Count.js

// 引入 UI 組件
import CountUI from '../../component/Count'

// 引入 connect 連接 UI 和 reudx
import { connect } from 'react-redux'

// 引入 action
import {createIncrease,createDecrease,createIncreaseaAsync} from '../../redux/actions/count'

// 第二個引數簡便的寫法
const mapDispatchToProps={
    fun1:createIncrease,
    fun2:createDecrease,
    fun3:createIncreaseaAsync
}


// 呼叫 connect 函式,回傳一個函式 , 再呼叫回傳的函式,回傳一個container組件 .此組件連接UI組件和redux
export default  connect(
    state=>({count:state}),
    mapDispatchToProps)(CountUI) // 連接 UI組件

component/Count.jsx

import React, { Component } from 'react'
// 不可引入 store

export default class Count extends Component {
    incread = () => {
        // 呼叫 方法
        this.props.fun1(1)

    }
    decread = () => {
        this.props.fun2(1)
    }
    increadAsync = () => {
        this.props.fun3(1,3000)
    }
    render() {
        return (
            <div>          {/** 獲取狀態 **/}
                <h1>結果為 :{this.props.count}</h1>&nbsp;
                <button className="btn btn-default" onClick={this.incread} >+</button>&nbsp;
                <button className="btn btn-default" onClick={this.decread} >-</button>&nbsp;
                <button className="btn btn-default" onClick={this.increadAsync} >異步加油</button>&nbsp;
            </div >
        )
    }
}

redux相關檔案不變

在 App.jsx 里使用 Count的容器組件 , 在 index.js 里使用 Provide組價 并且 傳入 store 即可

參考
redux概念之一:redux簡介
阮一峰的 redux 教程
尚硅谷react教程 redux部分

一萬 3千字,真干到流淚啊~ ,
阮一峰的教程和尚硅谷的教程都講的很好,我寫這些即方便自己以后回顧,也希望能幫助需要學習的人,
redux 自己出了一個開發者工具,可以檢測,測驗,回顧 state 的狀態 ,很好用,
對這個的使用我就不解釋了 ,尚硅谷的課程有講,看一看視頻便可

redux開發者工具的使用
如果你的谷歌游覽器訪問不了外網,那么可以在這個網站里下載插件
crx4下載redux devtools

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/301545.html

標籤:其他

上一篇:Java專案:學生資訊管理系統(java+SSM+jsp+mysql+maven)

下一篇:前端代碼自動生成器

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more