Redux 獨立的集中式狀態管理 js 庫 - 參見 My Git前端
不是 react 庫,能夠與 angular、vue 配合使用,一般和 react 用vue
yarn add reduxreact
import {createStore} from "redux"git
const store = createStore(myCounter); // 1. 核心 API - 參數是 reducer 函數---> 根據現有的狀態及 action 返回一個新的狀態,給 store 管理github
import {INCREMENT, DECREMENT} from "./action-types" // 有幾個 case,就要定義幾個 action 工廠chrome
export default function myCounter(state=0, action){ // 由 store 內部調用,初始值爲 0 ./redux/reducers編程
switch(action.type){ // action 必定要有一個 type 屬性redux
case INCREMENT:{return state+action.numbe;brack;}跨域
case INCREMENT:{return state+action.numbe;brack;}服務器
default: return state
}
}
<App store={store}
import {INCREMENT, DECREMENT} from "./action-types"
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
import * as actions from "../redux/actions";
this.props.store.dispatch(actions.increment(number)); // action creator 產生一個 action 對象,而後 dispatch 這個行爲 action
// 雖然等同於 this.props.store.dispatch({type: INCREMENT, number}); 可是通常不這麼作
// 工廠函數 - 每次調用,返回一個新的對象 - 每次都返回一個 actions
this.props.store.getState();
若是是 對象,則是 同步 action ---- 返回一個對象,描述行爲、state 參數
export const menuTitle = (menuTitle)=>({tyle: SETMENUTITLE, data: menuTitle})
若是是 函數,則是 異步 action
返回一個 函數,該函數接收一個 dispatch 參數
該函數內部進行異步操做,有告終果之後,再 dispatch 同步 action
export const login = ()=>{
return dispatch=>{
// 1. 執行異步代碼
const result = await requestLogin(username, password);
// 2. 分發同步 action
if(result.status === 0){
}else{
}
}
}
根據現有的 state 和 action 生成新的 state
存儲狀態數據的對象
維護着 state 和 reducer
核心方法
對象 action
何時用 redux?
某個組件的狀態須要共享
一個組件須要改變全局狀態
一個組件須要改變另外一個組件的狀態
整體原則: 能不用就不用,若是不用比較吃力才考慮使用
不用 redux 時的集中狀態管理?
將多個組件的共用狀態放在共同的父組件中
將狀態的相關方法定義在與狀態相同的組件中
官方實例分析?
redux 編程:
---------------------------------------------------------------------------------------------------------
src/redux/store.js
import {createStore} from "redux"
import reducer from "./reducer"
export default creareStore(reducer); // 建立 store 對象,內部會第一次自調用 reducer 函數獲得一個初始的狀態值進行保存
---------------------------------------------------------------------------------------------------------
src/redux/reducer.js
import {INCREMENT, DECREMENT} form "./action-types"
export default function count(state=1 action){ // 管理 count 就能夠叫 count,state 自己就是要管理的數據,第一次展現顯示 1
switch(action.type){
case INCREMENT:{return state+action.number;}
case INCREMENT:{return state-action.number;}
default: return state; // 不作任何處理
}
}
---------------------------------------------------------------------------------------------------------
src/redux/actions.js // 包含 n 個 action-creator 函數
import {INCREMENT, DECREMENT} form "./action-types"
export const increate = (number)=>({type: INCREMENT, number});
export const decreate = (number)=>({type: DECREMENT, number});
---------------------------------------------------------------------------------------------------------
src/redux/action-types.js // 多個 js 共用
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
---------------------------------------------------------------------------------------------------------
src/index.js
import React from "react"
import ReactDOM from "react-dom"
import App from "./App.jsx"
import store from "./redux/store"
ReactDOM.render(<App store={store} />, document.getElementById("root"));
store.subscribe(()=>{
ReactDOM.ummountComponentAtNode(document.getElementById("root")); // 先卸載原來的組件
ReactDOM.render(<App store={store} />, document.getElementById("root"));
})
---------------------------------------------------------------------------------------------------------
src/App.jsx
import React, {PureComponent} from "react"
import * as actions from "./redux/actions"
export default class App extends PureComponent{
increment = ()=>{
const number = +this.refs.numberSelect.value;
this.props.store,dispatch(actions.increment(number));
}
decrement = ()=>{
const number = +this.refs.numberSelect.value;
this.props.store,dispatch(actions.decrement(number));
}
render(){
const count = this.props.store.getState();
}
}
問題: react 與 redux 耦合度太強了,直接使用了 store
解決: 使用 react 的插件庫 react-redux ---- 簡化 react 中使用 redux
----------------------------------------- react 與 redux 的鏈接庫--------------------------------------------
Provider
向全部容器組件提供 store
connect(生成 容器組件,負責向 UI 組件傳遞標籤屬性
第一參數: 函數 ---- 通常屬性從 state 中獲取
state=>({title: state.menuTitle})
第二參數: 原始函數/簡寫對象{actionCreator1, action2}---- 函數屬性,執行 dispatch 分發 action-creator
)(UI組件)
---------------------------------------------------------
src/index.js
import React from "react"
import ReactDOM from "react-dom"
import App from "./App.jsx"
import store from "./redux/store"
import {Provider} from "react-redux"
-------------------------------------------------------------------------------------------------------------------
src/App.jsx
import React, {PureComponent} from "react"
import {connect} from 'react-redux'
imoprt Counter from "./components/Counter"
imoprt {increment, decrement]} from "./redux/actions"
function mapStateToProps(state){ // 讀取 state 數據,並將其映射成 UI 組件的通常屬性
return {count: state}
}
function mapDispatchToProps(dispatch){ // 爲 UI 組件映射函數屬性,函數內部必須 dispatch,分發 action,產生新的 state,從新 render
return {
incremrnt: number=>dispatch(increment(number))
decremrnt: number=>dispatch(decrement(number))
}
}
export default connect(
mapStateToProps, // 用來肯定向 UI 組件傳遞哪一些通常屬性 count
mapDispatchToProps // 用來肯定向 UI 組件傳遞哪些函數屬性 increment、decrement
)(Counter) // 用 connect 函數包裝一下 App 組件,返回一個新的組件對象
-------------------------------------------------------------------------------------------------------------------
src/components/Counter.jsx
1
react-redux 將組件分爲
UI 組件
不會使用任何 redux 相關的語法
最終,值仍是要被 store 管理的 ,getState()、dispatch()、
容器組件: 經過 connect 包裝 UI 組件生成的組件,內部能夠看見 store
1. 向 UI 組件傳遞通常屬性,屬性值 會以 state 傳遞
傳遞 狀態 以及操做 store 的相關函數到 reducer 中
2. 屬性值函數內部必然執行 dispatch 去分發 action
最終的簡潔寫法-------------------------------------------------------------------------------------
redux 異步編程
下載 異步中間件 yarn add redux-thunk
store.js
import thunk from "redux-thunk" // 中間件,擴展 redux 使其能夠 action-creator 能夠返回 函數
import {createStore, applyMiddleware} from "redux"
import reducer from "./reducer"
export default createStore(reducer, applyMiddleware(thunk));
actions.js 紅中增長 異步 action
返回的是一個函數,函數會接收一個參數:dispatch
dispatch函數能夠執行異步代碼, 有告終果,再分發一個同步的 action
export const increment = (number)=>({type:"increment", number})
export const incrementAsync = number=>{
return dispatch=>{
setTimeout(()=>{
dispatch(increment(number))
}, 1000)
}
}
redux 與 chrome 調試工具
yarn add redux-devtools-extension
combineReducers()
純函數 ---- 一樣的輸入,獲得一樣的輸出
不得修改參數 {...state, username: "test"}
不得調動 系統 I/O 的 API
不能調動不純的 Date.now() 或者 Math.random() 等函數
高階函數 ---- 參數是函數 或者 返回值是函數
filter、map、addEventListener、
高階組件 ---- 函數接收一個組件,產生的新組件
connect
前端項目 和 後臺服務器項目 各自獨立運行
會產生 資源未找到 或者 跨域
前端項目 置於 後臺服務器項目的 public
問題:
BrowserRouter 傳遞 state ---- 以至於訪問 被置爲後臺路由處理了
解決:
自定義中間件處理
後臺沒有一個頁面可以處理時,查看是否有前臺頁面能夠返回
前臺路由路徑 不能與 後臺路由路徑 同樣
專門的組件頁面 應對 404 和 500 頁面
啊