1.背景介紹
react是單向數據流,一級一級組件傳遞這個過程是不能越級的,爲了解決深度嵌套, redux橫空出世
2. redux
安裝:npm/cnpm i redux
(1). 分清兩個state
Redux中的state和React中的state完全不是一回事,React中的state是組件內部自己的狀態信息,而Redux中的state是Redux自己的數據
(2). Redux
redux工作流:
a.store
store:首先要創建一個對象store,這個對象有各種方法,用來讓外界獲取Redux的數據(store.getState),或者讓外界來修改Redux中的數據(store.dispatch)
b.action
action:描述我要幹啥,一般是一個對象的形式,其中有一個type字段是必須要有的,比如:{ type:‘撩妹’ },還可以帶點數據{ type:‘交朋友’,money: 100 }
c.reducer
reducer: 根據不同的action type處理邏輯
3. React-redux
安裝:npm/cnpm i react-redux
在React-redux中有兩個比較關鍵的概念:Provider和connect方法。
a.Provider
一般我們都將頂層組件包裹在Provider組件之中,這樣的話,所有組件就都可以在react-redux的控制之下了,但是store必須作爲參數放到Provider組件中去。這個組件的目的是讓所有組件都能夠訪問到Redux中的數據。
b.connet
用法:connect(mapStateToProps, mapDispatchToProps)(MyComponent)
mapStateToProps
接收一個state,返回一個對象。 mapDispatchToProps
接收一個 dispatch
組成的對象。
4. demo使用
index.js: provider包含組件最外層,將store傳給最頂級組件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {Provider} from 'react-redux';
import store from './store/index';
ReactDOM.render(<Provider store={store}><App /></Provider>,
document.getElementById('root')
);
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
store/index.js: combineReducers合併所有模塊的reducer; createStore將ruduces轉化爲store
import {createStore, combineReducers} from 'redux'
import user from './user'
let reduces = combineReducers({
user: user
})
export default createStore(reduces)
store/user.js: 抽象的reducer
import {SET_NAME, ADD_AGE} from '../actions'
function userReducer(state={ name: 'david', age: 18 }, action) {
switch(action.type) {
case SET_NAME:
return {
...state,
name: action.name
};
case ADD_AGE:
return {
...state,
age: state.age + action.age
};
default:
return state;
}
}
export default userReducer
actions.js: 定義type
export const SET_NAME = 'set_name'
export const ADD_AGE = 'add_age'
Home.js: 組件中使用connect, 可以得到redux的state,可以改變state的方法
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {SET_NAME, ADD_AGE} from '../actions';
class Home extends Component {
constructor(...args) {
super(...args);
this.state = {
inputName: ''
}
}
handelChangeName = (e) => {
this.setState({
inputName: e.target.value
})
}
/**
* @description 改變名稱
*/
changeName = (e) => {
this.props.setName(this.state.inputName)
}
/**
* @description 改變年齡
*/
changeAge = (e) => {
this.props.addAge(3)
}
render() {
return (
<div>
<div>name: {this.props.name}</div>
<div>age: {this.props.age}</div>
<input type="text" placeholder="請輸入名字" value={this.state.inputName} onChange={this.handelChangeName} onBlur={this.changeName}></input>
<button onClick={this.changeAge}>+3</button>
</div>
);
}
}
export default connect((state, props) => {
return state.user
}, {
setName(name){
return {
type: SET_NAME,
name
};
},
addAge(age){
return {
type: ADD_AGE,
age
};
}
})(Home)
或者使用dispatch({type: SET_NAME, name: this.state.inputName}) 也可以達到相同的目的。
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {SET_NAME, ADD_AGE} from '../actions';
class Home extends Component {
constructor(...args) {
super(...args);
this.state = {
inputName: ''
}
}
handelChangeName = (e) => {
this.setState({
inputName: e.target.value
})
}
/**
* @description 改變名稱
*/
changeName = (e) => {
// this.props.setName(this.state.inputName)
this.props.dispatch({type: SET_NAME, name: this.state.inputName})
}
/**
* @description 改變年齡
*/
changeAge = (e) => {
// this.props.addAge(3)
this.props.dispatch({type: ADD_AGE, age: 3})
}
render() {
return (
<div>
<div>name: {this.props.name}</div>
<div>age: {this.props.age}</div>
<input type="text" placeholder="請輸入名字" value={this.state.inputName} onChange={this.handelChangeName} onBlur={this.changeName}></input>
<button onClick={this.changeAge}>+3</button>
</div>
);
}
}
// export default connect((state, props) => {
// return state.user
// }, {
// setName(name){
// return {
// type: SET_NAME,
// name
// };
// },
// addAge(age){
// return {
// type: ADD_AGE,
// age
// };
// }
// })(Home)
export default connect((state) => {
return state.user
})(Home)
最後推薦使用方式:
import React, {Component} from 'react'
import {connect} from 'react-redux';
import {SET_NAME, ADD_AGE} from '../actions';
class Home extends Component {
constructor(...args){
super(...args)
this.state = {
inputName: ''
}
}
handelChangeName = (e) => {
this.setState({
inputName: e.target.value
})
}
render() {
return (
<div> dashboard
<div>name: {this.props.user.name}</div>
<div>age: {this.props.user.age}</div>
<input type="text" placeholder="請輸入名字" value={this.state.inputName} onChange={this.handelChangeName} onBlur={() => this.props.changeName(this.state.inputName)}></input>
<button onClick={this.props.changeAge}>+3</button>
</div>
);
}
}
// 不用裝飾器設置 Redux
const mapStateToProps = (state) => {
return { user: state.user }
}
const mapDispatchToProps = (dispatch, ownProps) => ({
changeName: (name) =>
{
dispatch({type: SET_NAME, name: name})
},
changeAge: () => {
dispatch({type: ADD_AGE, age: 3})
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard)
總結:
I. 單向數據流
state->component->action->state...
II.redux——集中狀態管理
provider:包在組件最外面
connect:狀態映射
reducer:狀態對象
action: 狀態更新