日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

redux 简明学习

發布時間:2025/3/15 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redux 简明学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

核心概念

  redux專注于狀態管理,把所有的狀態都存在一個對象中。核心概念包括:store、state、action、reducer

【store】

  store是保存數據的地方,redux提供createStore函數來生成 Store。函數參數是后面要介紹的reducer

import { createStore } from 'redux' const store = createStore(reducer)

【state】

  state是store的某個時刻的快照,可以通過store.getState()取得當前時刻的state

const state = store.getState()

【action】

  action用來改變state。action是一個對象,其中的type屬性是必須的,其他的屬性一般用來設置改變state需要的數據

const action = {type: 'ADD_ONE',num: 1 }

  store.dispatch()是發出action的唯一方法

const action = {type: 'ADD_ONE',num: 1 } store.dispatch(action)

【reducer】

  reducer 是一個函數,它接受action和當前state作為參數,返回一個新的state

import { createStore } from 'redux' const store = createStore(reducer) const reducer = (state = 10, action) => {switch (action.type) {case 'ADD_ONE':return state + action.num;default: return state;} };

  當store.dispatch發送過來一個新的action,store就會自動調用reducer,得到新的state

簡單實例

  多余的概念不再介紹,下面用上面介紹的這四個核心概念實現一個簡單的實例,將create-react-app中index.js文件內容更改如下,即可運行

//第一步,創建action const addOne = {type: 'ADD',num: 1 } const addTwo = {type: 'ADD',num: 2 } const square = {type: 'SQUARE' }//第二步,創建reducer let math = (state = 10, action) => {switch (action.type) {case ADD:return state + action.numcase SQUARE:return state * statedefault:return state} } //第三步,創建store import { createStore } from 'redux' const store = createStore(math)//第四步,測試,通過dispatch發出action,并通過getState()取得當前state值 console.log(store.getState()) //默認值為10store.dispatch(addOne) //發起'+1'的action console.log(store.getState()) //當前值為10+1=11store.dispatch(square) //發起'乘方'的action console.log(store.getState()) //當前值為11*11=121store.dispatch(addTwo) //發起'+2'的action console.log(store.getState()) //當前值為121+2=123

  結果如下

目錄結構

  下面對目錄結構進行劃分

  1、一般地,將action.type設置為常量,這樣在書寫錯誤時,會得到報錯提示

// constants/ActionTypes.js export const ADD = 'ADD' export const SQUARE = 'SQUARE'

  2、可以將addOne對象和addTwo對象整合成add函數的形式

// action/math.js import { ADD, SQUARE } from '../constants/ActionTypes' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE }

  3、根據action.type的分類來拆分reducer,最終通過combineReducers方法將拆分的reducer合并起來。上例中的action類型都是數字運算,無需拆分,只需進行如下變化

reducer/math.js // reducer/math.js import { ADD, SQUARE } from '../constants/ActionTypes' const math = (state = 10, action) => {switch (action.type) {case ADD:return state + action.numcase SQUARE:return state * statedefault:return state} } export default math

 reducer/index.js

// reducer/index.js import { combineReducers } from 'redux' import math from './math' const rootReducer = combineReducers({math }) export default rootReducer

  4、將store存儲到store/index.js文件中

// store/index.js import { createStore } from 'redux' import rootReducer from '../reducer' export default createStore(rootReducer)

  5、最終,根路徑下的index.js內容如下所示

import store from './store' import {add, square} from './action/math'console.log(store.getState()) //默認值為10store.dispatch(add(1)) //發起'+1'的action console.log(store.getState()) //當前值為10+1=11store.dispatch(square) //發起'乘方'的action console.log(store.getState()) //當前值為11*11=121store.dispatch(add(2)) //發起'+2'的action console.log(store.getState()) //當前值為121+2=123

  最終目錄路徑如下所示

  最終結果如下所示

?

UI層

  前面的示例中,只是redux的狀態改變,下面利用UI層來建立view和state的聯系,將根目錄下的index.js的內容更改如下

import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square } from './action/math'ReactDOM.render(<div store={store}><p>{store.getState().math}</p><input type="button" onClick={() => store.dispatch(add(1))} value="+1" /><input type="button" onClick={() => store.dispatch(add(2))} value="+2" /><input type="button" onClick={() => store.dispatch(square)} value="乘方" /></div>,document.getElementById('root') )

  雖然可以顯示數字,但是點擊按鈕時,卻不能重新渲染頁面

【store.subscribe()】

  接下來介紹store.subscribe()方法了,該方法用來設置監聽函數,一旦state發生變化,就自動執行這個函數。該方法的返回值是一個函數,調用這個函數可以解除監聽

  下面將示例代碼更改如下

import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square } from './action/math'const render = () => ReactDOM.render(<div store={store}><p>{store.getState().math}</p><input type="button" onClick={() => store.dispatch(add(1))} value="+1" /><input type="button" onClick={() => store.dispatch(add(2))} value="+2" /><input type="button" onClick={() => store.dispatch(square)} value="乘方" /></div>,document.getElementById('root') )render() store.subscribe(render)

  代碼終于可以正常運行了?

異步

  redux默認只處理同步,對于API請求這樣的異步任務則無能為力

  接下來嘗試使用axios的get方法來請求下面這個API

https://jsonplaceholder.typicode.com/posts/2

  獲取的數據如下

{"userId": 1,"id": 2,"title": "qui est esse","body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" }

  然后,將其id值設置為state.math的值

  代碼修改如下

// constants/ActionTypes.js export const ADD = 'ADD' export const SQUARE = 'SQUARE' export const SET = 'SET'// action/math.js import { ADD, SQUARE, SET } from '../constants/ActionTypes' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE } export const setNum = num => ({type: SET,num})// reduce/math.js import { ADD, SQUARE,SET } from '../constants/ActionTypes' const math = (state = 10, action) => {switch (action.type) {case ADD:return state + action.numcase SQUARE:return state * statecase SET:return action.numdefault:return state} } export default math// index.js import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square, setNum } from './action/math' import axios from 'axios' let uri = 'https://jsonplaceholder.typicode.com/posts/2' const render = () => ReactDOM.render(<div store={store}><p>{store.getState().math}</p><input type="button" onClick={() => {axios.get(uri).then(res => {store.dispatch(store.dispatch(setNum(res.data.id)))})}} value="設置Num" /><input type="button" onClick={() => store.dispatch(add(1))} value="+1" /><input type="button" onClick={() => store.dispatch(add(2))} value="+2" /><input type="button" onClick={() => store.dispatch(square)} value="乘方" /></div>,document.getElementById('root') ) render() store.subscribe(render)

  但是,雖然API是異步操作,但store.dispatch并不是異步,而axios通過get方法請求回來數據后,store.dispatch在axios中的then方法中同步取得數據

【redux-thunk】

  如果要使用真正的異步操作,即把axios方法封裝到store.dispatch中,需要使用redux-thunk中間件

  首先,使用npm進行安裝

npm install --save redux-thunk

  然后,使用applyMiddleware來使用thunk中間件

import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import rootReducer from '../reducer' export default createStore(rootReducer,applyMiddleware(thunk))

  接著來定義setNum這個action creator,然后在index.js文件的DOM加載完成后就發出setNum

  [注意]如果action是一個對象,則它就是一個action,如果action是一個函數,則它是一個action creator,即action制造器

  修改的代碼如下

// action/math.js import { ADD, SQUARE, SET } from '../constants/ActionTypes' import axios from 'axios' const uri = 'https://jsonplaceholder.typicode.com/posts/2' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE } export const setNum = () => (dispatch, getState) => {return axios.get(uri).then(res => {dispatch({type: SET,num: res.data.id})}) }// index.js import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square, setNum } from './action/math' const render = () => ReactDOM.render(<div store={store}><p>{store.getState().math}</p><input type="button" onClick={() => store.dispatch(setNum())} value="設置Num" /><input type="button" onClick={() => store.dispatch(add(1))} value="+1" /><input type="button" onClick={() => store.dispatch(add(2))} value="+2" /><input type="button" onClick={() => store.dispatch(square)} value="乘方" /></div>,document.getElementById('root') ) render() store.subscribe(render)

【提示信息】

  如果做的更完備一點,應該把異步請求時的提示信息也加上。增加一個fetch的action,用于控制fetch過程的提示信息及顯示隱藏情況

  代碼更改如下

action/fetch.js // action/fetch.js import { SET_FETCH_MESSAGE, HIDE_FETCH_MESSAGE } from '../constants/ActionTypes' export const startFetch = { type: SET_FETCH_MESSAGE,message: '開始發送異步請求' } export const successFetch = { type: SET_FETCH_MESSAGE, message: '成功接收數據' } export const failFetch = { type: SET_FETCH_MESSAGE, message: '接收數據失敗' } export const hideFetchMessage = { type: HIDE_FETCH_MESSAGE } action/math.js // action/math.js import { ADD, SQUARE, SET } from '../constants/ActionTypes' import { startFetch, successFetch, failFetch, hideFetchMessage } from './fetch' import axios from 'axios' const uri = 'https://jsonplaceholder.typicode.com/posts/2' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE } export const setNum = () => (dispatch, getState) => {dispatch(startFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 500)return axios.get(uri).then(res => {setTimeout(() => {dispatch(successFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 500)dispatch({ type: SET, num: res.data.id })}, 1000)}).catch(err => {dispatch(failFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 500)}) } constants/ActionTypes.js // constants/ActionTypes.js export const ADD = 'ADD' export const SQUARE = 'SQUARE' export const SET = 'SET' export const SET_FETCH_MESSAGE = 'SET_FETCH_MESSAGE' export const HIDE_FETCH_MESSAGE = 'HIDE_FETCH_MESSAGE' reduce/fetch.js // reduce/fetch.js import { SET_FETCH_MESSAGE,HIDE_FETCH_MESSAGE } from '../constants/ActionTypes' const initState = {message:'',isShow:false } const fetch = (state = initState, action) => {switch (action.type) {case SET_FETCH_MESSAGE:return {isShow: true, message: action.message}case HIDE_FETCH_MESSAGE:return { isShow: false, message: '' }default:return state} } export default fetch index.js // index.js import store from './store' import React from 'react' import ReactDOM from 'react-dom' import { add, square, setNum } from './action/math' const render = () => ReactDOM.render(<div store={store}><p>{store.getState().math}</p><input type="button" onClick={() => store.dispatch(setNum())} value="設置Num" /><input type="button" onClick={() => store.dispatch(add(1))} value="+1" /><input type="button" onClick={() => store.dispatch(add(2))} value="+2" /><input type="button" onClick={() => store.dispatch(square)} value="乘方" />{store.getState().fetch.isShow && <p>{store.getState().fetch.message}</p>}</div>,document.getElementById('root') ) render() store.subscribe(render)

?

展示和容器

  下面來介紹react-redux。前面的代碼中,我們是通過store.subscribe()方法監控state狀態的變化來更新UI層的。而使用react-redux,可以讓組件動態訂閱狀態樹。狀態樹一旦被修改,組件能自動刷新顯示最新數據

  react-redux將所有組件分成兩大類:展示組件和容器組件。展示組件只負責UI呈現,所有數據由參數props提供;容器組件則負責管理數據和業務邏輯,帶有內部狀態,可使用redux的API。要使用react-redux,就要遵守它的組件拆分規范

【provider】

  react-redux提供Provider組件,可以讓容器組件默認可以拿到state,而不用當容器組件層級很深時,一級級將state傳下去

  將index.js文件更改如下

// index.js import React from 'react' import ReactDOM from 'react-dom' import store from './store' import MathContainer from './container/MathContainer' import { Provider } from 'react-redux' ReactDOM.render(<Provider store={store}><MathContainer /></Provider>,document.getElementById('root') )

  按照組件拆分規范,將原來index.js中相關代碼,分拆到container/MathContainer和component/Math這兩個組件中

【connect】

  react-redux提供connect方法,用于從展示組件生成容器組件。connect的意思就是將這兩種組件連接起來

import { connect } from 'react-redux' const MathContainer = connect()(Math);

  Math是展示組件,MathContainer就是由React-redux通過connect方法自動生成的容器組件

  為了定義業務邏輯,需要給出下面兩方面的信息

  1、輸入邏輯:外部的數據(即state對象)如何轉換為展示組件的參數

  2、輸出邏輯:用戶發出的動作如何變為Action對象,從展示組件傳出去

  因此,connect方法的完整API如下

import {connect} from 'react-redux' const MathContainer= connect(mapStateToProps,mapDispatchToProps )(Math)

  上面代碼中,connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了展示組件的業務邏輯。前者負責輸入邏輯,即將state映射到UI組件的參數(props),后者負責輸出邏輯,即將用戶對展示組件的操作映射成Action

【mapStateToProps()】

  mapStateToProps建立一個從外部的state對象到展示組件的props對象的映射關系。作為參數,mapStateToProps執行后應該返回一個對象,里面的每一個鍵值對就是一個映射。

const mapStateToProps = (state) => {return {num: getNum(state) } }

  mapStateToProps的第一個參數總是state對象,還可以使用第二個參數,代表容器組件的props對象。使用ownProps作為參數后,如果容器組件的參數發生變化,也會引發展示組件重新渲染

const mapStateToProps = (state,ownProps) => {return {num: getNum(state) } }

  mapStateToProps會訂閱Store,每當state更新的時候,就會自動執行,重新計算展示組件的參數,從而觸發展示組件的重新渲染。connect方法可以省略mapStateToProps參數,那樣,展示組件就不會訂閱Store,就是說Store的更新不會引起展示組件的更新

【mapDispatchToProps】

  mapDispatchToProps是connect函數的第二個參數,用來建立展示組件的參數到store.dispatch方法的映射。也就是說,它定義了用戶的哪些操作應該當作action,傳給Store。它可以是一個函數,也可以是一個對象

  如果mapDispatchToProps是一個函數,會得到dispatch和ownProps(容器組件的props對象)兩個參數

const mapDispatchToProps = (dispatch,ownProps) => {return {onSetNumClick: () => dispatch(setNum())} }

  mapDispatchToProps作為函數,應該返回一個對象,該對象的每個鍵值對都是一個映射,定義了展示組件的參數怎樣發出action

  如果mapDispatchToProps是一個對象,它的每個鍵名也是對應展示組件的同名參數,鍵值應該是一個函數,會被當作action creator,返回的action會由redux自動發出

  因此,上面的寫法簡寫如下所示

const mapDispatchToProps = {onsetNumClick: () => setNum() }

?

最終結構

  由于store目錄中,只能一個index.js文件,且不會有內容擴展,將其更改為根目錄下的store.js文件

  將其他的目錄都變成復數形式,最終的目錄結構如下所示

  詳細代碼如下所示,且可訪問github線上地址

【components】

// components/Math.js import React from 'react' const Math = ({num,isShow,fetchMessage,onSetNumClick,onAddOneClick,onAddTwoClick,onSqureClick }) => (<section><p>{num}</p><input type="button" onClick={onSetNumClick} value="設置Num" /><input type="button" onClick={onAddOneClick} value="+1" /><input type="button" onClick={onAddTwoClick} value="+2" /><input type="button" onClick={onSqureClick} value="乘方" />{isShow && <p>{fetchMessage}</p>}</section> )export default Math

【containers】

// containers/MathContainer.js import { connect } from 'react-redux' import Math from '../components/Math' import { getNum } from '../selectors/math' import { getFetchMessage, getFetchIsShow } from '../selectors/fetch' import { setNum, add, square } from '../actions/math' const mapStateToProps = state => {return {num: getNum(state),fetchMessage: getFetchMessage(state),isShow: getFetchIsShow(state)} } const mapDispatchToProps = {onSetNumClick: () => setNum(),onAddOneClick: () => add(1),onAddTwoClick: () => add(2),onSqureClick: () => square } const MathContainer = connect(mapStateToProps, mapDispatchToProps)(Math) export default MathContainer

【actions】

actions/fetch.js // actions/fetch.js import { SET_FETCH_MESSAGE, HIDE_FETCH_MESSAGE } from '../constants/ActionTypes' export const startFetch = { type: SET_FETCH_MESSAGE,message: '開始發送異步請求' } export const successFetch = { type: SET_FETCH_MESSAGE, message: '成功接收數據' } export const failFetch = { type: SET_FETCH_MESSAGE, message: '接收數據失敗' } export const hideFetchMessage = { type: HIDE_FETCH_MESSAGE } actions/math.js // actions/math.js import { ADD, SQUARE, SET } from '../constants/ActionTypes' import { startFetch, successFetch, failFetch, hideFetchMessage } from './fetch' import axios from 'axios' const uri = 'https://jsonplaceholder.typicode.com/posts/2' export const add = num => ({ type: ADD, num }) export const square = { type: SQUARE } export const setNum = () => (dispatch, getState) => {dispatch(startFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 300)return axios.get(uri).then(res => {dispatch(successFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 300)dispatch({ type: SET, num: res.data.id })}).catch(err => {dispatch(failFetch)setTimeout(() => {dispatch(hideFetchMessage)}, 300)}) }

【constants】

// constants/ActionTypes.js export const ADD = 'ADD' export const SQUARE = 'SQUARE' export const SET = 'SET' export const SET_FETCH_MESSAGE = 'SET_FETCH_MESSAGE' export const HIDE_FETCH_MESSAGE = 'HIDE_FETCH_MESSAGE'

【reducers】

reducers/fetch.js // reducers/fetch.js import { SET_FETCH_MESSAGE,HIDE_FETCH_MESSAGE } from '../constants/ActionTypes' const initState = {message:'',isShow:false } const fetch = (state = initState, action) => {switch (action.type) {case SET_FETCH_MESSAGE:return {isShow: true, message: action.message}case HIDE_FETCH_MESSAGE:return { isShow: false, message: '' }default:return state} } export default fetch reducers/index.js // reducers/index.js import { combineReducers } from 'redux' import math from './math' import fetch from './fetch' const rootReducer = combineReducers({math,fetch })export default rootReducer reduces/math.js // reduces/math.js import { ADD, SQUARE,SET } from '../constants/ActionTypes' const math = (state = 10, action) => {switch (action.type) {case ADD:return state + action.numcase SQUARE:return state * statecase SET:return action.numdefault:return state} } export default math

【selectors】

// selectors/fetch.js export const getFetchMessage = state => state.fetch.message export const getFetchIsShow = state => state.fetch.isShow // selectors/math.js export const getNum = state => state.math

【根目錄】

index.js // index.js import React from 'react' import ReactDOM from 'react-dom' import store from './store' import MathContainer from './containers/MathContainer' import { Provider } from 'react-redux' ReactDOM.render(<Provider store={store}><MathContainer /></Provider>,document.getElementById('root') )  store.js // store.js import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import rootReducer from './reducers' export default createStore(rootReducer,applyMiddleware(thunk))

轉自:http://www.cnblogs.com/xiaohuochai/p/8447826.html

.

轉載于:https://www.cnblogs.com/crazycode2/p/8652972.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的redux 简明学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。