参考博客 & 文档
0.安装
npm i redux react-redux --save
yarn add redux react-redux --save
1.store
store用于存放数据的中心
// store/index.js
import { createStore } from 'redux';
import rootReducers from './reducers/index.js'
const store = createStore(rootReducers); // 传入 reducers 集合
2.reducer
reducer 用于声明初始数据,以及修改数据逻辑。创建一个 user.js 的 reducer,reducer 函数接收初始 state 数据和 action,action 是修改数据的唯一途径,在 reducer 中根据 action.type 执行不同的逻辑,最后返回 state,state 类型为数组或对象,需要返回全新的 state,不可在原 state 上进行修改
// store/reducers/user.js
const initUser = {
name: 'Tom'
}
export default function(state = initUser, action) {
switch(action.type) {
case 'EDIT_USER_NAME':
return Object.assign({}, state, action.payload)
default:
return state
}
}
combineReducers 用于合成多个 recuder
// store/reducers/index.js
import { combineReducers } from 'redux';
import userReducer from './user'
import goodlistReducer from './goodlist'
export default combineReducers({
userReducer,
goodlistReducer
})
3.获取 store
引入 store.js,三个主要的函数
store.getState():获取 store 数据
store.dispatch(action):修改数据
store.subscribe():监听数据变化
import React, { Component } from 'react'
import store from './store'
store.subscribe(() => {
console.log(store.getState()) // 监听数据发生变化,获取最新的数据
});
class Home extends Component {
render() {
console.log(store)
let user = store.getState().userReducer
return (
<p onClick={() => {
store.dispatch({ // store.dispatch(action),提交 action 修改数据
type: 'EDIT_USER_NAME',
payload: {name: 'Jerry'}
})
}}>
About {user.name}
</p>
)
}
}
export default Home
4.action
修改数据的唯一方法:通过 store.dispatch() 提交 action,reducer 会接收 action,进行判断 & 修改
store.dispatch({
type: 'EDIT_USER_NAME',
payload: {name: 'Jerry'}
})
dispatch() 中的对象就是 action,需要写明 action 类型:type,参数:payload。这种写法较为繁琐,可通过 action creator 代替,action creator 是一个返回对象的函数,这样在 dispatch() 中只需要传入函数,而不需要写整个 action 对象
// store/actions/user.js
export const editUserName = (payload) => {
return {
tyoe: 'EDIT_USER_NAME',
payload
}
}
import { editUserName } from './store/actions/user.js'
store.dispatch(editUserName({name: 'Jerry'}))
5.异步 action
// store/actions/user.js
export const editUserName = (payload) => {
setTimeout(() => {
return {
tyoe: 'EDIT_USER_NAME',
payload
}
}, 1000)
}
执行dispatch()会出现错误。解决方法:添加 redux-thunk 中间件
npm i redux-thunk --save
yarn add redux-thunk --save
// store/index.js,添加中间件
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducers from './reducers'
export default createStore(
rootReducers,
applyMiddleware(thunk)
)
thunk 的一个优点是它的结果可以再次被 dispatch。修改 action
// store/actions/user.js
export const editUserName = (payload) => {
return function (dispatch) {
setTimeout(() => {
dispatch({
type: 'EDIT_USER_NAME',
payload
})
}, 1000)
}
}
6.react-redux
一个 React 专用的库 React-Redux
import React, { Component } from 'react'
import { editUserName } from './store/acitons/user'
import { connect } from 'react-redux'
class Home extends Component {
render() {
let { user } = this.props // 获取state
return (
<p onClick={() => {
// this.props.dispatch(editUserName({name: 'Jerry'}))
this.editUserName({name: 'Jerry'})
}}>About {user.name}</p>
)
}
}
// mapStateToProps,将 store 中的数据,传递到当前组件的 props 中
const mapStateToProps = (state) => {
return {
user: state.userReducer
}
}
export default connect(mapStateToProps, { editUserName })(Home)
connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。React-Redux 提供 Provider 组件,可以让容器组件拿到 state 数据
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import App from './App'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
7.Chrome调试
安装 Redux Devtools,修改 store.js
import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducers'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default createStore(
reducer,
composeEnhancers(applyMiddleware(thunk))
)