react項目配置及redux使用流程(詳細記錄)

react項目配置及redux使用流程(詳細記錄)

以TodoList爲例,項目地址:https://github.com/mandyshen9...

react項目創建及配置

首先創建react項目:

creact-react-app reactdemo

修改默認配置:

create-react-app 的默認配置進行自定義,這裏我們使用 react-app-rewired(一個對 create-react-app 進行自定義配置的社區解決方案)。

$ yarn add react-app-rewired customize-cra

修改package.json:

/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test",
+   "test": "react-app-rewired test",
}

然後在項目根目錄創建一個 config-overrides.js 用於修改默認配置。

module.exports = function override(config, env){
  // do staff with the webpack config...
  return config
}

配置按需加載:

babel-plugin-import 是一個用於按需加載組件代碼和樣式的 babel 插件(原理),現在我們嘗試安裝它並修改 config-overrides.js 文件。

yarn add babel-plugin-import

修改config-overrides.js文件:

const { override, fixBabelImports } = require('customize-cra')
module.exports = override(
  fixBabelImports('import',{
    libraryName: 'antd', // 或其他第三方組件庫名稱
    libiaryDirectory: 'es', // 組件位置
    style: 'css',
  })
)

配置less

配置less: 我們可以引入 customize-cra 中提供的 less 相關的函數 addLessLoader 來幫助加載 less 樣式,同時修改 config-overrides.js 文件如下。

yarn add less less-loader
const { override, fixBabelImports, addLessLoader } = require('customize-cra')
module.exports = override(
  fixBabelImports('import',{
    libraryName: 'antd', // 或其他第三方組件庫名稱
    libiaryDirectory: 'es', // 組件位置
    style: true,
  }),
  addLessLoader({
    javascriptEnabled: true,
  })
)

<hr/>
<hr/>

redux的使用

clipboard.png

安裝redux:

yarn add redux

從圖片中可以看出,Redux工作流程中有四個部分,最重要的就是store這個部分,因爲它把所有的數據都放到了store中進行管理。在編寫代碼的時候,因爲重要,所以要優先編寫store。

(1)創建src/store/index.js,就是整個項目的store文件。

/**
 * index.js 文件就是整個項目的store文件
 */

import { createStore } from 'redux' // 引入 createStore方法
import reducer from './reducer' // 引入reducer
const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() // 使瀏覽器中redux-devtool插件生效
) // 創建數據存儲倉庫
export default store // 將倉庫暴露出去

(2)創建src/store/reducer.js,有管理能力的模塊。

store只是一個倉庫,它並沒有管理能力,它會把接收到的action自動轉發給reducer。

/**
 * reducer暴露出去的就是一個方法函數,有兩個參數:state 和 action。
 * state: 是整個項目中需要管理的數據信息。
 */

/**
 * 一定要注意: reducer裏只能接收state,不能改變state。
 * 不要認爲把業務邏輯寫在了reducer中,那改變state值的一定是reducer。
 * 其實不然,reudcer只是返回了更改的數據,操作的是newState,但是並沒有更改store中的state數據,store拿到了reducer的數據,自己對自己進行了更新。
 */
const defaultState = {} // 默認數據
export default (state = defaultState, action) => {
  if (action.type === CHANGE_INPUT) {
    let newState = JSON.parse(JSON.stringify(state)) // 深度拷貝state
    newState.inputValue = action.value
    return newState
  }
  if (action.type === ADD_ITEM) {
    let newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)  //push新的內容到列表中去
    newState.inputValue = ''
    return newState
  }
  // 其他類似操作流程...
  return state
}

(3)組件獲取state中的數據。

import store from '../store/index' // 在組件中引入store

class TodoList extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState() // 從store中獲取state數據
    store.subscribe(this.storeChange) // 訂閱Redux的狀態
  }

  /**
   * 當訂閱的redux狀態變化時,使用setState()方法,將新的數據存入state中。
   */
  storeChange = () => {
    this.setState(store.getState())
  }
}

(4) 創建src/store/actionTypes.js

如果需要action的地方我們就自己命名一個type,會出現兩個基本問題:

  • 這些types如果不統一管理,不利於大型項目的複用,甚至會產生冗餘代碼。
  • 因爲action裏的type,一定要和reducer裏的type一一對應,所以這部分代碼或字母寫錯後,瀏覽器裏並沒有明確的報錯,這給調試帶來了極大的困難。

所以新建立一個actionTypes.js文件,然後把type集中放到文件中進行管理。

export const ADD_ITEM = 'addItem'
export const // ...
// ...

(5) 創建src/store/actionCreators.js

把所有的redux action放到一個文件裏進行管理。

import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM, GET_LIST } from './actionTypes'

export const changeInputAction = (value) => ({
  type: CHANGE_INPUT,
  value
})

export const addItemAction = () => ({
  type: ADD_ITEM
})

export const deleteItemAction = (index) => ({
  type: DELETE_ITEM,
  index
})

export const getListAction = (data) => ({
  type: GET_LIST,
  data
})

// ...

下面通過button的點擊事件來熟悉redux流程。

組件:

import React, { Component } from 'redux'
import { addItemAction } from '.././store/actionCreators'

class List extends Component {
  constructor(props){
    super(props)
    this.state = store.getState()
    store.subscribe(this.storeChange)
  }
  storeChange = () => {
    this.setState(store.getState())
  }

  clickBtn = () => {
    action = addItemAction() // 返回一個對象{type: ADD_ITEM}
    store.dispatch(action) // 通過dispatch()方法將action傳遞給store
  }

  render(){
    return(
      <div>
        <button onClick={this.clickBtn}>增加</button>
      <div/>
    )
  }
}

store/index.js,整個項目的store文件:

// store/index.js
import { createStore } from 'redux' // 引入 createStore方法
import reducer from './reducer' // 引入reducer
const store = createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
) // 創建數據存儲倉庫
export default store // 將倉庫暴露出去

store/reducer.js:

// store/reducer.js
import { ADD_ITEM } from './actionTypes'

const defaultState = {
  inputValue: 'Write Something',
  list: []
} // 默認數據

export default (state = defaultState, action) => {
  if (action.type === ADD_ITEM) {
    let newState = JSON.parse(JSON.stringify(state))
    newState.list.push(newState.inputValue)  //push新的內容到列表中去
    newState.inputValue = ''
    return newState
  }
  return state
}

store/actionTypes.js:

// store/actionTypes.js
export const ADD_ITEM = 'addItem'

store/actionCreators.js:

// store/actionCreators.js
import { ADD_ITEM } from './actionTypes'

export const addItemAction = () => ({
  type: ADD_ITEM
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章