1. 实现效果
上面是Count组件,下面是Flag组件。
Count组件中,点击点击+1按钮,数值加一,点击清零按钮,数值清零,同时数值传递给Flag组件同步显示。
Flag组件中,点击login可以切换为true,点击logout切换为false,同时将状态传递给Count组件同步显示。
2. 安装依赖包
npm install react-redux redux redux-thunk redux-devtools-extension
3. 文件结构
使用了redux,需要在UI组件外套一层容器组件。由于是父子关系,容器组件通过props向里层的UI组件传递参数,将容器组件放在containers文件夹下。
使用redux,需要单独创建redux文件夹,包括actions文件夹和reducers文件夹,还有向外暴露常量的constant.js和store.js。
4. 详细代码
1. Count 组件
(1)组件定义
通过class定义的是UI组件,向外暴露的是容器组件,容器组件通过props向UI组件传递状态和方法。
// src/containers/Count/index.jsx
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { add, clear } from '../../redux/actions/count';
// UI组件
class Count extends Component {
add = () => {
// 通知redux
this.props.add(1);
};
clear = () => {
this.props.clear();
};
render() {
return (
<Fragment>
<h2>当前求和为:{this.props.count}</h2>
<h3>当前Flag:{this.props.flag ? 'true' : 'false'}</h3>
<button onClick={this.add}>点击+1</button>
<button onClick={this.clear}>清零</button>
</Fragment>
);
}
}
// 暴露容器组件
export default connect(
// 1.状态
state => ({ count: state.sum, flag: state.flagState }),
// 2.方法
{ add, clear }
)(Count);
(2)创建action
该文件用于创建action对象。
// src/redux/actions/count.js
// 为Count组件创建action对象
// 引入常量
import { ADD, CLEAR } from '../constant';
// 创建加一action对象的函数
export const add = data => ({
type: ADD,
data,
});
// 创建清零action对象的函数
export const clear = data => ({
type: CLEAR,
data,
});
(3)reducer
该文件用于判断type的类型,加工数据。
// src/redux/reducers/count.js
// 为Count组件创建一个reducer
// reducer接收两个参数:之前状态的preState,动作对象action
import { ADD, CLEAR } from '../constant.js';
// 设定初始状态
const initState = 0;
export default function addReducer(preState = initState, action) {
// 从action中获取type和data
const { type, data } = action;
// 根据type决定如何加工数据
switch (type) {
case ADD:
return preState + data;
case CLEAR:
return 0;
// 初始化动作
default:
return preState;
}
}
2. Flag 组件
(1)组件定义
// src/containers/Flag/index.jsx
import React, { Component, Fragment } from 'react';
import { connect } from 'react-redux';
import { login, logout } from '../../redux/actions/flag';
class Flag extends Component {
login = () => {
this.props.login();
};
logout = () => {
this.props.logout();
};
render() {
return (
<Fragment>
<h2>当前Flag:{this.props.flag ? 'true' : 'false'}</h2>
<h3>当前求和为:{this.props.count}</h3>
<button onClick={this.login}>login</button>
<button onClick={this.logout}>logout</button>
</Fragment>
);
}
}
export default connect(state => ({ flag: state.flagState, count: state.sum }), { login, logout })(
Flag
);
(2)创建action
// src/redux/actions/flag.js
// 为Flag组件创建action对象
// 引入常量
import { LOGIN, LOGOUT } from '../constant';
// 创建加一action对象的函数
export const login = data => ({
type: LOGIN,
data,
});
// 创建加一action对象的函数
export const logout = data => ({
type: LOGOUT,
data,
});
(3)reducer
// src/redux/reducers/flag.js
// reducer接收两个参数:之前状态的preState,动作对象action
import { LOGIN, LOGOUT } from '../constant.js';
// 设定初始状态
const initState = false;
export default function addReducer(preState = initState, action) {
const { type } = action;
switch (type) {
case LOGIN:
return true;
case LOGOUT:
return false;
default:
return preState;
}
}
3. 汇总所有 reducer
所有的组件的reducer要汇总到一个文件中,并向外暴露redux中存放的状态对象。
// src/redux/reducers/index.js
// 汇总所有的reducer
import { combineReducers } from 'redux';
import sum from './count';
import flagState from './flag';
export default combineReducers({
sum,
flagState,
});
4. 常量文件
// src/redux/constant.js
export const LOGIN = 'login';
export const LOGOUT = 'logout';
export const ADD = 'add';
export const CLEAR = 'clear';
5. store
引入汇总后的rudecer,暴露store。
// src/redux/store.js
// 整个文档只有一个store对象
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import allRudecers from './reducers';
import { composeWithDevTools } from 'redux-devtools-extension';
// 暴露store
export default createStore(allRudecers, composeWithDevTools(applyMiddleware(thunk)));
6. 项目入口文件 index.js
引入store,并将<App />用<Provider store={store}></Provider>包裹,这样<App />下所有的组件都能接收到store了。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.jsx';
import store from './redux/store';
import { Provider } from 'react-redux';
ReactDOM.render(
// Provider包裹App,目的:让App所有的后代容器组件都能接收到store
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);