目录
一、redux介绍
Redux 基于三个基本原则:
单一数据源:整个应用的状态存储在一个对象树中
状态是只读的:唯一改变状态的方法是触发 action
使用纯函数执行修改:reducer 是纯函数,接收旧 state 和 action,返回新 state
二、安装
npm install redux react-redux
三、基本实现步骤
3.1 创建Action Types
// actionTypes.js
export const INCREMENT = "INCREMENT";
export const DECREMENT = "DECREMENT";
3.2 创建counterAction
// store/actions/counterAction.js
import { INCREMENT, DECREMENT } from "../../utils/actionTypes";
export const increment = () => ({
type: INCREMENT,
});
export const decrement = () => ({
type: DECREMENT,
});
3.3 创建counterReducer
// store/reducers/counterReducer.js
import { INCREMENT, DECREMENT } from "../../utils/actionTypes";
const initialState = {
count: 0,
};
export default function counterReducer(state = initialState, action) {
switch (action.type) {
case INCREMENT:
return { ...state, count: state.count + 1 };
case DECREMENT:
return { ...state, count: state.count - 1 };
default:
return state;
}
}
3.4 结合所有Reducer
// store/reducers/index.js
import { combineReducers } from "redux";
import counterReducer from "./counterReducer";
export default combineReducers({
counter: counterReducer,
});
3.5 创建store
// store/index.js
import { createStore } from "redux";
import reducers from "./reducers";
const store = createStore(reducers);
export default store;
3.6 入口文件中提供store
// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import store from "./store";
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
3.7 在组件中的使用
import React from "react";
import { connect } from "react-redux";
import { increment, decrement } from "./store/actions/counterAction";
function App(props) {
const { count, increment, decrement } = props;
return (
<div>
<div>数值:{count}</div>
<button onClick={() => increment()}>点我+1</button>
<button onClick={() => decrement()}>点我-1</button>
</div>
);
}
const mapStateToProps = (state) => ({
count: state.counter.count, // store/reducers/index.js中的counter映射
});
const mapDispatchToProps = {
increment,
decrement,
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
3.8 使用thunk实现异步支持
3.8.1 安装
npm install redux-thunk
3.8.2 在counterAction中添加异步操作
// store/actions/counterAction.js
import { INCREMENT, DECREMENT } from "../../utils/actionTypes";
export const increment = () => ({
type: INCREMENT,
});
export const decrement = () => ({
type: DECREMENT,
});
export const fetchIncrement = (timeout) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, timeout);
};
};
3.8.3 在store文件中添加异步支持
// store.js
import { createStore, applyMiddleware } from "redux";
import { thunk } from "redux-thunk";
import reducers from "./reducers";
const store = createStore(reducers, applyMiddleware(thunk));
export default store;
3.8.4 在组件中进行异步操作
import React from "react";
import { connect } from "react-redux";
import {
increment,
decrement,
fetchIncrement,
} from "./store/actions/counterAction";
function App(props) {
const { count, increment, decrement, fetchIncrement } = props;
return (
<div>
<div>数值:{count}</div>
<button onClick={() => increment()}>点我+1</button>
<button onClick={() => decrement()}>点我-1</button>
<button onClick={() => fetchIncrement(1000)}>点我异步+1</button>
</div>
);
}
const mapStateToProps = (state) => ({
count: state.counter.count, // store/reducers/index.js中的counter映射
});
const mapDispatchToProps = {
increment,
decrement,
fetchIncrement,
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
3.9 函数式组件使用hooks代替connect
// App.js
import React from "react";
import { useSelector, useDispatch } from "react-redux";
import {
increment,
decrement,
fetchIncrement,
} from "./store/actions/counterAction";
export default function App(props) {
const { count } = useSelector((state) => state.counter); // store/reducers/index.js中的counter映射
const dispatch = useDispatch();
return (
<div>
<div>数值:{count}</div>
<button onClick={() => dispatch(increment())}>点我+1</button>
<button onClick={() => dispatch(decrement())}>点我-1</button>
<button onClick={() => dispatch(fetchIncrement(1000))}>点我异步+1</button>
</div>
);
}