前置工作
利用 npx create-react-app
创建一个 react 项目。
接着安装 redux
和 react-redux
- redux 用于 JavaScript 状态容器,提供可预测化的状态管理。
- react-redux 是 react 专用的插件库,用来简化 react 应用中使用 redux 的操作。
js
npm install --save redux
npm install --save react-redux
使用
这里由 标题 title 组件 和 表格 table 组件互相获取到对方的数据
index.js 入口文件
该文件在项目根目录下 src 文件夹里
js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 引入 store 状态管理的文件
import store from './store';
// 引入 Provider组件
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode> // 默认有的 表示开启严格模式
// 该组件包裹着 App组件,在该组件属性传递 store,能让 App 的所有后代组件都能接收到 store
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
reportWebVitals();
App.jsx
在该文件传入在页面展示的组件
js
import React, { Component } from 'react'
// 标题组件
import TitleControl from './containers/titleControl/index';
// 表格组件
import Person from './containers/Person/index';
export default class App extends Component {
render() {
return (
<div className="App">
<TitleControl />
<br/>
<Person />
</div>
);
}
}
创建组件容器文件夹

titleControl 标题 组件
在目录下创建该结构并创建我们想要的组件文件
js
import React, { Component } from 'react'
import { connect } from 'react-redux'
// 传入 title 的状态 action
import { createEditAction } from '../../store/actions/title'
class Count extends Component {
editTitle = ()=> {
const name = this.nameNode.value
// 用于修改 title 的状态
this.props.editTitle(name)
this.nameNode.value = ''
}
render() {
return (
<div>
<h2>{this.props.title}</h2>
// 在这里使用到 表格 store 里的数据
<div>当前有{this.props.persons.length}人</div>
<input ref={c=> this.nameNode = c} type="text" placeholder='输入标题' />
<button onClick={this.editTitle}>确认</button>
</div>
)
}
}
export default connect(
state => ({title: state.title, persons: state.persons}), // state 可以获取到 store 的状态树
{editTitle: createEditAction} // 执行相应的状态操作
)(Count)
person 表格 组件
js
import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import { connect } from 'react-redux'
import { createAddPersonAction } from '../../store/actions/person'
class Person extends Component {
addPerson = ()=> {
const name = this.nameNode.value
const grade = this.gradeNode.value
let personObj = {
id: nanoid(),
name,
grade
}
this.props.handleAdd(personObj)
this.nameNode.value = ''
this.gradeNode.value = ''
}
render() {
return (
<div>
<input ref={c=> this.nameNode = c} type="text" placeholder='输入名字' />
<input ref={c=> this.gradeNode = c} type="text" placeholder='输入等级' />
<button onClick={this.addPerson}>添加</button>
<table border="1">
<thead>
<tr>
<td>姓名</td>
<td>等级</td>
</tr>
</thead>
<tbody>
{
this.props.persons.map( p => {
return <tr key={p.id}>
<td>{p.name}</td>
<td>{p.grade}</td>
</tr>
})
}
</tbody>
</table>
// 这里使用到 title 状态
<div>当前标题为 => {this.props.title}</div>
</div>
)
}
}
export default connect(
state => ({persons: state.persons, title: state.title}),
{handleAdd: createAddPersonAction}
)(Person)
当要使用到 id 值,通常 id 是不可重复的,可以使用 nanoid 来创建独一无二的 id
安装 npm add nanoid
创建 store 状态文件夹

store 状态集合文件
legacy_createStore 用于创建 store
combineReducers 将多个不同 reducer 函数集合,合并成一个最终的 reducer 函数,可以根据传递对象的 key 来获取不同 reducer 状态数据
js
import { combineReducers, legacy_createStore } from "redux";
import countReaducer from "./reducers/title"
import personReducer from "./reducers/person";
const allReducer = combineReducers({
title: countReaducer,
persons: personReducer
})
const store = legacy_createStore(allReducer);
export default store
title 的 reducer
创建状态管理的目录
js
// reducer/title.js
const defaultState = '标题'
/*
state:状态数据
action:为一个动作对象,有着两个属性 type 和 data
type:标识属性, 值为字符串, 唯一, 必要属性
data:数据属性, 值类型任意, 可选属性
例子:{ type: 'add_number', data: 5}
*/
const reducer = (
state = defaultState,
action
) => {
switch(action.type) {
case "edit":
state = action.data;
break;
default:
break;
}
return state;
}
export default reducer;
title 的 action
js
// action/title.js
const createEditAction = data => ({ type: 'edit', data })
export { createEditAction}
table 的 reducer
js
import { ADD_PERSON } from "../constant";
const initState = [{id: '001', name: '孙悟空', grade: 999}]
const personReducer = (
preState = initState,
action
) => {
const { type, data } = action
switch (type) {
case ADD_PERSON:
return [data, ...preState]
default:
return preState
}
}
export default personReducer
table 的 action
js
import { ADD_PERSON } from '../constant'
export const createAddPersonAction = personObj => ({type: ADD_PERSON, data:personObj})
但我们使用 action 中要经常填写 type 值,容易出错,所以可以创建一个常量文件来管理这些变量
js
// constant.js
// 用于定义 action 中 type 类型常量
export const INCREMANT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'
页面效果
这样 title 组件可以使用到 table 中的数据, table 组件也可以获取到 title 的标题

总结
- 创建 store,用 combineReducers 合并多个不同 reducer,再用 legacy_createStore 创建出最终的 store 状态树
- 入口文件 index.js 使用 react-redux 的 Provider 组件包裹 App ,让后续的组件都能获取到 store 状态树
- 创建各个 reducer,reducer 里面使用的 action 是根据 type 来执行对应的数据的操作
- 创建容器组件文件,里面定义 UI组件用来展示,并用 react-redux 的 connect 来连接 UI组件
- connect 里面可以传递两个值,可以用来获取由 Provider 组件传递的 store 状态树 和 进行对应 action 操作