一些小型項目,只使用 React 徹底夠用了,數據管理使用props、state便可,那何時須要引入Redux呢? 當渲染一個組件的數據是經過props從父組件中獲取時,一般狀況下是A –> B,但隨着業務複雜度的增長,有多是這樣的:A –> B –> C –> D –> E,E須要的數據須要從A那裏經過props傳遞過來,以及對應的E –> A逆向傳遞callback。組件BCD是不須要這些數據的,可是又必須經由它們來傳遞,這樣不太友好,並且傳遞的props以及callback對BCD組件的複用也會形成影響。或者兄弟組件之間想要共享某些數據,也不是很方便傳遞、獲取等。諸如此類的狀況,就有必要引入Redux`了。
注:其實 A --> B --> C --> D --> E 這種狀況,React不使用props層層傳遞也是能拿到數據的,使用Context便可。javascript
redux的核心概念就是store、action、reducer
State 是隻讀的 react文檔中說唯一改變 state 的方法就是觸發 action,奇怪的是 咱們說State是隻讀的,可是爲啥如今又說能夠修改了呢,其實咱們並非直接修改state,action」是用來向 store 表示要修改 state 的載體。因此咱們並無直接設置state的方法,使用了dispatch(action) 發送 action 至 store 是惟一改變 state 的方式
必須擁有type屬性,用來描述發生什麼,action經過reducer處理生成newState後纔可以更改store信息。可是爲了更好的語義編程,Redux經過語句store.dispatch(action)來更新store,reducer對action的處理在內部處理。
java
僅僅只是根據action.type處理一下須要更新的state
react
//store/index.js編程
/*引入createStore 是用來建立一個數據源對象保存咱們的數據的*/
import { createStore, applyMiddleware, compose } from 'redux';
import { createLogger } from 'redux-logger';
//引用數據源
// store是引用的reducer
// action會觸發reducer
import allreducers from './reducers/index';
//數據處理後會返回給數據源 才能取到最新的數據 在根組件index裏獲取
const logger = createLogger();
const store = createStore(
allreducers,
applyMiddleware(logger)
)
console.log(store)
function listerner () {
store.getState();
}
store.subscribe(listerner);
export default store;複製代碼
Store保存了整個應用的單一狀態樹,全部容器組件都須要從store中讀取,咱們能夠store做爲屬性傳遞給每一個組件,子組件經過props獲取,可是若是嵌套過深,寫起來會很麻煩。還好,react-redux提供一個叫provider的組件,他可讓全部組件均可以訪問到store(他的實現原理其實是利用了react的context功能),而沒必要顯示的一層層傳遞了。
import { Provider } from 'react-redux'
import store from './store';
ReactDOM.render(
<Provider store={store}> <BrowserRouter> {routes } </BrowserRouter> </Provider>,
document.getElementById('app')
);複製代碼
//reducers/index.jsredux
import * as Types from 'src/store/constants'
import { combineReducers } from 'redux';
const initState = {
isLogin: "未登陸",
themecolor: "red",
count: 0
}
const loginReducer = (state = initState.isLogin ,action) => {
switch (action.type) {
case Types.LOGIN_TYPE:
return state = action.isLogin
default:
return state
}
}
const themeReducer = (state = initState.themecolor ,action) => {
switch (action.type) {
case Types.THEME_TYPE:
return state = action.themecolor
default:
return state
}
}
const counterReducer = (state = initState.count, action) => {
switch(action.type) {
case Types.ADD_TYPE: return state + 1;
default: return state;
}
}
export default combineReducers({
isLogin:loginReducer,
themecolor:themeReducer,
count:counterReducer
})複製代碼
注意:combineReducers() 函數的做用是把多個 reducer 合併成一個最終的 reducer 函數。
bash
//constants/index.jsapp
/*常量統一保存,便於管理*/
export const LOGIN_TYPE = "LOGIN_TYPE"
export const THEME_TYPE = "THEME_TYPE"
export const ADD_TYPE = "ADD_TYPE"複製代碼
actions/index.jside
import * as Types from 'src/store/constants'
export const loginAction = function(isLogin) {
return {
type: Types.LOGIN_TYPE,
isLogin
}
}
export const themeAction = function(themecolor) {
return {
type: Types.THEME_TYPE,
themecolor
}
}
export const addAction = () => {
return {
type: Types.ADD_TYPE
}
}複製代碼
組件調用函數式編程
import React, {PureComponent} from "react"
import store from 'src/store'
import { loginAction,themeAction,addAction } from 'src/store/actions'
const counterfn = () => {
document.getElementById("counter").innerHTML = store.getState().count
}
store.subscribe(counterfn);
class NwdLogin extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
}
render () {
var state = store.getState();
return (
<div> <div id="counter"></div> <div> <button onClick={() => store.dispatch(addAction())}>add </button> </div> </div>
)
}
}
export default NwdLogin複製代碼
、
函數
注意:在不使用react-redux的狀況下 必須使用store.subscribe(listener), store更新後回調listener,回調函數裏面能夠調用store.getStore()來獲取更新後得state喲~
react-redux,redux和react的橋樑工具。 react-redux將組建分紅了兩大類,UI組建component和容器組件container。
UI組件:
容器組件:
import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
}
render () {
console.log(this.props)
return (
<div> {this.props.isLogin} <button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button> </div>
)
}
}
const mapStateToProps = (state,ownProps) => {
return {
isLogin: state.isLogin,
themecolor: state.themecolor
}
}
const mapDispatchToProps = ((dispatch,ownPorps) => {
return {
loginAction: (isLogin) => dispatch({
type: "LOGIN_TYPE",
isLogin: isLogin
}),
themeAction: (themecolor) => dispatch({
type: "THEME_TYPE",
themecolor: themecolor
})
}
})
export default connect(mapStateToProps,mapDispatchToProps)(NwdLogin)複製代碼
1)connect()() 其實這兒是兩次函數調用。首先。connect() 返回了一個函數,而後咱們馬上調用了這個函數並給它傳遞進第二個括號內的參數。第二個參數通常是一個 React 組件這是一種常見的「函數式編程」的寫法。
2)connect() 的第一個參數是個返回了一個對象的函數 mapStateToProps,這個對象的屬性將會變成 React 組件中的「props」的屬性,你能夠看到他們的值來自 store 的 state。這裏我把這第一個參數命名爲「mapStateToProps」,如命名所示,是但願它來將全局 states 轉化成本地 component 的 props。 mapStateToProps() 將會接收到一個攜帶着完整的 Redux store 的參數 store,而後抽出本地組件須要的 states 轉換成 props。
3)
import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
}
render () {
console.log(this.props)
return (
<div> {this.props.isLogin} <button onClick={() => this.props.dispatch(loginAction("已登陸"))}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.dispatch(themeAction("#fff"))}>設置themecolor狀態{this.props.themecolor}</button> </div>
)
}
}
const mapStateToProps = (state,ownProps) => {
return {
isLogin: state.isLogin,
themecolor: state.themecolor
}
}
/*const mapDispatchToProps = ((dispatch,ownPorps) => { return { loginAction: (isLogin) => dispatch({ type: "LOGIN_TYPE", isLogin: isLogin }), themeAction: (themecolor) => dispatch({ type: "THEME_TYPE", themecolor: themecolor }) } })*/
export default connect(mapStateToProps)(NwdLogin)複製代碼
import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
@connect(
state => {
return {
isLogin: state.isLogin,
themecolor: state.themecolor
}
},
{
loginAction,
themeAction,
addAction
}
)
class NwdLogin extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
}
render () {
console.log(this.props)
return (
<div> {this.props.isLogin} <button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button> </div>
)
}
}
export default NwdLogin
複製代碼
bindActionCreators是redux的一個API,做用是將單個或多個ActionCreator轉化爲dispatch(action)的函數集合形式。 開發者不用再手動dispatch(actionCreator(type)),而是能夠直接調用方法。
import React, {PureComponent} from "react"
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
@connect(
state => {
return {
isLogin: state.isLogin,
themecolor: state.themecolor
}
},
dispatch => bindActionCreators({loginAction,themeAction,addAction},dispatch)
)
class NwdLogin extends React.Component {
constructor(props){
super(props)
}
componentDidMount() {
}
render () {
console.log(this.props)
return (
<div>
{this.props.isLogin}
<button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button>
<button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button>
</div>
)
}
}
export default NwdLogin
複製代碼