欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在 React 中使用 Redux 解決的問題小結(jié)

 更新時間:2022年10月23日 09:43:28   作者:皮蛋很白  
在 React 中組件通信的數(shù)據(jù)流是單向的,頂層組件可以通過 props 屬性向下層組件傳遞數(shù)據(jù),而下層組件不能直接向上層組件傳遞數(shù)據(jù),這篇文章主要介紹了使用react+redux實現(xiàn)彈出框案例,需要的朋友可以參考下

在 React 中使用 Redux 解決的問題

在 React 項目中未加入 Redux 時的問題

在 React 中組件通信的數(shù)據(jù)流是單向的,頂層組件可以通過 props 屬性向下層組件傳遞數(shù)據(jù),而下層組件不能直接向上層組件傳遞數(shù)據(jù)。要實現(xiàn)下層組件修改上層組件的數(shù)據(jù),需要上層組件傳遞修改數(shù)據(jù)的方法到下層組件。當項目越來越大的時候,組件之間傳遞數(shù)據(jù)以及傳遞修改數(shù)據(jù)的方法變得越來越困難。

在這里插入圖片描述

在 React 項目中加入 Redux 的好處

使用 Redux 管理數(shù)據(jù),由于 Store 獨立于組件,使得數(shù)據(jù)管理獨立于組件,解決了組件與組件之間傳遞數(shù)據(jù)困難的問題。

在這里插入圖片描述

React + Redux 安裝 Redux

在 react 項目中使用 redux 要下載兩個模塊

npm install redux react-redux

React 中 Redux 的工作流程

在 React 中 Redux 的工作流程有些變化:

  1. 組件通過 dispatch 方法觸發(fā) Action
  2. Store 接收 Action 并將 Action 分發(fā)給 Reducer
  3. Reducer 根據(jù) Action 類型對狀態(tài)進行更改并將更改后的狀態(tài)返回給 Store
  4. 組件訂閱了 Store 中的狀態(tài),Store 中的狀態(tài)更新會同步到組件

在這里插入圖片描述

React 計數(shù)器案例

React 實現(xiàn)

創(chuàng)建項目安裝模塊

# 創(chuàng)建項目(React 17 版本)
npx create-react-app myapp
# 安裝 redux
cd myapp
npm install redux

刪掉無用的文件

├─ src
│   ├─ App.css
│   ├─ App.test.js
│   ├─ index.css
│   ├─ logo.svg
│   ├─ reportWebVitals.js
│   └─ setupTests.js

初步實現(xiàn)

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux'

const initialState = {
  count: 0
}
function reducer (state = initialState, action) {
  switch (action.type) {
    case 'increment':
      return {
        count: state.count + 1
      }
      case 'decrement':
        return {
          count: state.count - 1
        }
      default:
        return state
  }
}
const store = createStore(reducer)

const increment = { type: 'increment' }
const decrement = { type: 'decrement' }

function Counter() {
  return <div>
    <button onClick={() => store.dispatch(increment)}>+</button>
    <span>{store.getState().count}</span>
    <button onClick={() => store.dispatch(decrement)}>-</button>
  </div>
}

store.subscribe(() => {
  ReactDOM.render(
    <React.StrictMode>
      <Counter />
    </React.StrictMode>,
    document.getElementById('root')
  );
})

console.log(store.getState())

ReactDOM.render(
  <React.StrictMode>
    <Counter />
  </React.StrictMode>,
  document.getElementById('root')
);

使用 Redux

開發(fā)時我們會把組件寫在單獨的文件中,如果將 Counter 組件單獨提取,就無法訪問 store 對象以及一些其它的問題,所以需要使用 redux。

安裝 react-redux

npm install react-redux

react-redux 用于讓 react 和 redux 完美結(jié)合,它僅僅提供兩個內(nèi)容:

  • Provider 組件
    • 它可以將創(chuàng)建出來的 store 放到全局,允許所有組件訪問
    • 可以解決將組件存儲在單獨文件中時,訪問 store
  • connect 方法
  • connect 方法會幫助訂閱 store,當 store 中的狀態(tài)發(fā)生變化,會重新渲染組件
    • 解決了需要手動訂閱更新組件狀態(tài)
  • connect 方法可以獲取 store 中的狀態(tài),映射到組件的 props 屬性中
  • connect 方法可以獲取 dispatch 方法,組件可以通過 props.dispatch訪問

在這里插入圖片描述

Provide 組件

  • Provider 組件要包裹項目中所有的組件,也就是應(yīng)該被放在最外層組件上
  • Provider 通過 store 屬性接收創(chuàng)建的 store 對象

connect 方法

  • 首先調(diào)用 connect 方法
    • 第一個參數(shù)是一個函數(shù)
      • 函數(shù)接收的第一個參數(shù),即組件中的狀態(tài) state
      • 函數(shù)要返回一個對象,該對象定義的屬性都會映射到組件的 props 屬性中
    • 第二個參數(shù)也是一個函數(shù)
      • 函數(shù)接收的第一個參數(shù),即 dispatch 方法
      • 函數(shù)要返回一個對象,可以定義觸發(fā) Action 的方法,它們同樣會被映射到組件的 props 屬性中
    • 返回一個方法
  • 繼續(xù)調(diào)用返回的方法,并傳遞當前的組件

修改代碼

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux'
import Counter from './components/Counter'
import { Provider } from 'react-redux'

const initialState = {
  count: 0
}
function reducer (state = initialState, action) {
  switch (action.type) {
    case 'increment':
      return {
        count: state.count + 1
      }
      case 'decrement':
        return {
          count: state.count - 1
        }
      default:
        return state
  }
}
const store = createStore(reducer)

ReactDOM.render(
  // 通過 provider 組件將 store 放在了全局,供所有組件可以訪問
  <React.StrictMode>
    <Provider store={store}>
      <Counter />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

提取的 Counter 組件

// src/components/Counter.js
import { connect } from 'react-redux'
function Counter(props) {
  return <div>
    <button onClick={() => props.dispatch({ type: 'increment' })}>+</button>
    <span>{props.count}</span>
    <button onClick={() => props.dispatch({ type: 'decrement' })}>-</button>
  </div>
}

const mapStateToProps = state => ({
  count: state.count
})

export default connect(mapStateToProps)(Counter)

使用 connect 第二個參數(shù)簡化組件

// src/components/Counter.js
import { connect } from 'react-redux'
function Counter({count, increment, decrement}) {
  return <div>
    <button onClick={increment}>+</button>
    <span>{count}</span>
    <button onClick={decrement}>-</button>
  </div>
}

const mapStateToProps = state => ({
  count: state.count
})

const mapDispatchToProps = dispatch => ({
  increment () {
    dispatch({ type: 'increment' })
  },
  decrement () {
    dispatch({ type: 'decrement' })
  }
})

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

使用 bindActionCreators 方法繼續(xù)簡化

觸發(fā) Action 的方法 incrementdecrement 的內(nèi)容基本是一樣的,redux 提供 bindActionCreators 方法生成一個函數(shù),來簡化這種重復(fù)性代碼。

  • 參數(shù)
    • actionCreators: 對象或返回對象的函數(shù)
      • key是生成函數(shù)的名稱
      • value是一個返回 Action 的函數(shù)
    • dispatch: 需傳遞Store 的 dispatch 方法
  • 返回一個對象,同 connect 接收的第二個參數(shù)
// src/components/Counter.js
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
function Counter({count, increment, decrement}) {
  return <div>
    <button onClick={increment}>+</button>
    <span>{count}</span>
    <button onClick={decrement}>-</button>
  </div>
}

const mapStateToProps = state => ({
  count: state.count
})

const mapDispatchToProps = dispatch => ({
  ...bindActionCreators({
    increment() {
      return { type: 'increment' }
    },
    decrement() {
      return { type: 'decrement' }
    }
  }, dispatch)
})

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

此時還沒有達到簡化的效果,可以將 actionCreators 提取到單獨的文件中。

// src\store\actions\counter.action.js
export const increment = () => ({ type: 'increment' })
export const decrement = () => ({ type: 'decrement' })
// src/components/Counter.js
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as counterActions from '../store/actions/counter.action'

function Counter({count, increment, decrement}) {
  return <div>
    <button onClick={increment}>+</button>
    <span>{count}</span>
    <button onClick={decrement}>-</button>
  </div>
}

const mapStateToProps = state => ({
  count: state.count
})

const mapDispatchToProps = dispatch => bindActionCreators(counterActions, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

代碼重構(gòu)

為了繼續(xù)演示 Redux 的相關(guān)內(nèi)容,將與 Redux 相關(guān)的代碼從 src/index.js中抽離出去,讓項目結(jié)構(gòu)更加合理。

  • 將 reducer 函數(shù)抽離到一個文件中
  • 將創(chuàng)建 store 的代碼手里到一個文件中
  • 將 Actions 的 type 抽象成模塊中的成員,好處是:

    編輯器有提示,避免寫錯

    編輯器自動插入模塊引入的代碼

將 Actions 的 type 抽象成模塊中的成員

// src\store\actions\counter.action.js
import { DECREMENT, INCREMENT } from "../const/counter.const"
export const increment = () => ({ type: INCREMENT })
export const decrement = () => ({ type: DECREMENT })

將 reducer 函數(shù)抽離到一個文件中

// src\store\reducers\counter.reducer.js
import { DECREMENT, INCREMENT } from "../const/counter.const"

const initialState = {
  count: 0
}
function reducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      return {
        count: state.count + 1
      }
    case DECREMENT:
      return {
        count: state.count - 1
      }
    default:
      return state
  }
}

export default reducer

將創(chuàng)建 store 的代碼手里到一個文件中

// src\store\index.js
import { createStore } from 'redux'
import reducer from './reducers/counter.reducer'

export const store = createStore(reducer)

修改后的 src/index.js

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from './components/Counter'
import { Provider } from 'react-redux'
import { store } from './store'

ReactDOM.render(
  // 通過 provider 組件將 store 放在了全局,供所有組件可以訪問
  <React.StrictMode>
    <Provider store={store}>
      <Counter />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
)

為 Action 傳遞參數(shù)

當前計數(shù)器對數(shù)字進行遞增/減的數(shù)值為 1,現(xiàn)在通過給 Action 傳遞參數(shù),允許自定義數(shù)值。

  • 傳遞參數(shù):調(diào)用觸發(fā) Action 函數(shù)的時候傳遞參數(shù)
  • 接收參數(shù):返回 Action 的函數(shù)接收參數(shù),添加到返回的 Action 對象中
  • 處理參數(shù):reducer 函數(shù)處理的時候,可以從 action 對象獲取這個參數(shù),進行處理

傳遞參數(shù):

// src/components/Counter.js
function Counter({ count, increment, decrement }) {
	// 修改 Counter 組件中調(diào)用 increment decrement 函數(shù)的地方
  return (
    <div>
      <button onClick={() => increment(5)}>+</button>
      <span>{count}</span>
      <button onClick={() => decrement(5)}>-</button>
    </div>
  )
}

接收參數(shù):

// src\store\actions\counter.action.js
import { DECREMENT, INCREMENT } from "../const/counter.const"
export const increment = payload => ({ type: INCREMENT, payload })
export const decrement = payload => ({ type: DECREMENT, payload })

處理參數(shù):

// src\store\reducers\counter.reducer.js
import { DECREMENT, INCREMENT } from "../const/counter.const"

const initialState = {
  count: 0
}
function reducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      return {
        count: state.count + action.payload
      }
    case DECREMENT:
      return {
        count: state.count - action.payload
      }
    default:
      return state
  }
}

export default reducer

Redux 彈出框

在頁面中顯示兩個按鈕:

  • 顯示:顯示彈出框
  • 隱藏:隱藏彈出框

初始化靜態(tài)內(nèi)容

Modal 組件

// src\components\Modal.js
function Modal() {
  const styles = {
    width: 200,
    height: 200,
    position: 'absolute',
    left: '50%',
    top: '50%',
    marginLeft: -100,
    marginTop: -100,
    backgroundColor: 'skyblue'
  }
  return (
    <div>
      <button>顯示</button>
      <button>隱藏</button>
      <div style={styles}></div>
    </div>
  )
}

export default Modal

修改 src/index.js

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { Provider } from 'react-redux'
import { store } from './store'

ReactDOM.render(
  // 通過 provider 組件將 store 放在了全局,供所有組件可以訪問
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
)

修改 src/App.js

// src\App.js
import Counter from './components/Counter'
import Modal from './components/Modal'

function App() {
  return (
    <div>
      <Counter />
      <Modal />
    </div>
  )
}

export default App

添加默認隱藏狀態(tài)

在 reducer 中添加顯示狀態(tài)的屬性

// src\store\reducers\counter.reducer.js
import { DECREMENT, INCREMENT } from "../const/counter.const"

const initialState = {
  count: 0,
  showStatus: false
}
function reducer(state = initialState, action) {...}

export default reducer

在組件中使用狀態(tài)

// src\components\Modal.js
import { connect } from 'react-redux'

function Modal({ showStatus }) {
  const styles = {
    width: 200,
    height: 200,
    position: 'absolute',
    left: '50%',
    top: '50%',
    marginLeft: -100,
    marginTop: -100,
    backgroundColor: 'skyblue',
    display: showStatus ? 'block' : 'none'
  }
  return (
    <div>
      <button>顯示</button>
      <button>隱藏</button>
      <div style={styles}></div>
    </div>
  )
}

const mapStateToProps = state => ({
  showStatus: state.showStatus
})

export default connect(mapStateToProps)(Modal)

定義操作按鈕

定義 Action 的 type

// src\store\const\modal.const.js
export const SHOWMODAL = 'showModal'
export const HIDEMODAL = 'hideModal'

定義生成 Action 的函數(shù)

// src\store\actions\modal.actions.js
import { HIDEMODAL, SHOWMODAL } from "../const/modal.const"

export const show = () => ({ type: SHOWMODAL })
export const hide = () => ({ type: HIDEMODAL })

創(chuàng)建觸發(fā) Action 的方法并使用

// src\components\Modal.js
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as modalActions from '../store/actions/modal.actions'

function Modal({ showStatus, show, hide }) {
  const styles = {
    width: 200,
    height: 200,
    position: 'absolute',
    left: '50%',
    top: '50%',
    marginLeft: -100,
    marginTop: -100,
    backgroundColor: 'skyblue',
    display: showStatus ? 'block' : 'none'
  }
  return (
    <div>
      <button onClick={show}>顯示</button>
      <button onClick={hide}>隱藏</button>
      <div style={styles}></div>
    </div>
  )
}

const mapStateToProps = state => ({
  showStatus: state.showStatus
})

const mapDispatchToProps = dispatch => bindActionCreators(modalActions, dispatch)

export default connect(mapStateToProps, mapDispatchToProps)(Modal)

修改 reducer 函數(shù),處理變更:

// src\store\reducers\counter.reducer.js
import { DECREMENT, INCREMENT } from '../const/counter.const'
import { HIDEMODAL, SHOWMODAL } from '../const/modal.const'

const initialState = {
  count: 0,
  showStatus: false
}
function reducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      // reducer 返回的對象會替換 store 中的狀態(tài)對象,所以要將其它狀態(tài)也包含進去
      return {
        ...state,
        count: state.count + action.payload
      }
    case DECREMENT:
      return {
        ...state,
        count: state.count - action.payload
      }
    case SHOWMODAL:
      return {
        ...state,
        showStatus: true
      }
    case HIDEMODAL:
      return {
        ...state,
        showStatus: false
      }
    default:
      return state
  }
}

export default reducer

注意:reducer 返回的對象會替換 store 中的狀態(tài)對象,所以要將其它狀態(tài)也包含進去

衍生的問題

在 reducer 函數(shù)中匹配了所有狀態(tài)的變更,當項目越來越大,狀態(tài)越來越多時,管理起來就很麻煩。

所以要將 rreducer 函數(shù)進行拆分。

拆分合并 reducer 拆分

將 modal 拆分出去

// src\store\reducers\modal.reducer.js
import { HIDEMODAL, SHOWMODAL } from '../const/modal.const'
const initialState = {
  show: false
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case SHOWMODAL:
      return {
        ...state,
        showStatus: true
      }
    case HIDEMODAL:
      return {
        ...state,
        showStatus: false
      }
    default:
      return state
  }
}

export default reducer
// src\store\reducers\counter.reducer.js
import { DECREMENT, INCREMENT } from '../const/counter.const'

const initialState = {
  count: 0,
}
function reducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT:
      // reducer 返回的對象會替換 store 中的狀態(tài)對象,所以要將其它狀態(tài)也包含進去
      return {
        ...state,
        count: state.count + action.payload
      }
    case DECREMENT:
      return {
        ...state,
        count: state.count - action.payload
      }
    default:
      return state
  }
}

export default reducer

合并

合并 reducer 需要借助 redux 提供的 combineReducers 方法。

combineReducers 把一個由多個不同 reducer 函數(shù)作為 value 的 object 對象,合并成一個最終的 reducer 函數(shù),然后就可以對這個 reducer 調(diào)用 createStore 方法。

合并后的 reducer 可以調(diào)用各個子 reducer,并把它們返回的結(jié)果合并成一個 state 對象。

由 combineReducers() 返回的 state 對象,會將傳入的每個 reducer 返回的 state 按傳遞給 combineReducers() 時對應(yīng)的 key 進行命名。

// src\store\reducers\root.reducer.js
import { combineReducers } from 'redux'
import CounterReducer from './counter.reducer'
import ModalReducer from './modal.reducer'

// 合并后的 store 為 { counter: { count: 0 }, modal: { showStatus: false } }
export default combineReducers({
  counter: CounterReducer,
  modal: ModalReducer
})
// src\store\index.js
import { createStore } from 'redux'
import RootReducer from './reducers/root.reducer'

export const store = createStore(RootReducer)

調(diào)整組件

因為 store 中的數(shù)據(jù)結(jié)構(gòu)發(fā)生變化,所以還需要調(diào)整下組件中獲取狀態(tài)的地方

// src\store\index.js
import { createStore } from 'redux'
import RootReducer from './reducers/root.reducer'

export const store = createStore(RootReducer)
// src\components\Modal.js
const mapStateToProps = state => ({
  showStatus: state.modal.showStatus
})

到此這篇關(guān)于在 React 中使用 Redux 解決的問題的文章就介紹到這了,更多相關(guān)React Redux 案例內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你在react中創(chuàng)建自定義hooks

    教你在react中創(chuàng)建自定義hooks

    簡單來說就是使用自定義hook可以將某些組件邏輯提取到可重用的函數(shù)中。 自定義hook是一個從use開始的調(diào)用其他hook的Javascript函數(shù),下面看下react中創(chuàng)建自定義hooks的相關(guān)知識,感興趣的朋友一起看看吧
    2021-11-11
  • React模擬實現(xiàn)Vue的keepAlive功能

    React模擬實現(xiàn)Vue的keepAlive功能

    Vue中,keep-alive組件可以緩存組件狀態(tài),在路由切換時重新掛載,實現(xiàn)這一功能在React中并不簡單,但我們可以借助一個第三方庫——react-activation 來模擬Vue的keep-alive功能,需要的朋友可以參考下
    2024-10-10
  • 詳解react關(guān)于事件綁定this的四種方式

    詳解react關(guān)于事件綁定this的四種方式

    這篇文章主要介紹了詳解react關(guān)于事件綁定this的四種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • react實現(xiàn)無限循環(huán)滾動信息

    react實現(xiàn)無限循環(huán)滾動信息

    這篇文章主要為大家詳細介紹了react實現(xiàn)無限循環(huán)滾動信息,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • React 性能優(yōu)化之非必要的渲染問題解決

    React 性能優(yōu)化之非必要的渲染問題解決

    本文主要介紹了React 性能優(yōu)化之非必要的渲染問題解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React深入淺出分析Hooks源碼

    React深入淺出分析Hooks源碼

    在react類組件(class)寫法中,有setState和生命周期對狀態(tài)進行管理,但是在函數(shù)組件中不存在這些,故引入hooks(版本:>=16.8),使開發(fā)者在非class的情況下使用更多react特性
    2022-11-11
  • 解決React報錯Rendered more hooks than during the previous render

    解決React報錯Rendered more hooks than during

    這篇文章主要為大家介紹了React報錯Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • react 組件表格固定底部的實現(xiàn)代碼

    react 組件表格固定底部的實現(xiàn)代碼

    在React中,要實現(xiàn)一個組件表格并且固定底部,可以使用CSS的固定定位或絕對定位來實現(xiàn),下面通過示例代碼給大家分享react 組件表格固定底部的實現(xiàn)代碼,感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • 教你如何實現(xiàn)在react項目中嵌入Blazor

    教你如何實現(xiàn)在react項目中嵌入Blazor

    這篇文章主要介紹了如何實現(xiàn)在react現(xiàn)有項目中嵌入Blazor,通過這個案例我們可以知道 blazor也可以像react那樣嵌入在任何的現(xiàn)有項目中,并且使用方便,需要的朋友可以參考下
    2023-01-01
  • antd+react中upload手動上傳單限制上傳一張

    antd+react中upload手動上傳單限制上傳一張

    本文主要介紹了antd+react中upload手動上傳單限制上傳一張,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06

最新評論