手把手带你用 react-redux 实现组件数据共享

前置工作

利用 npx create-react-app 创建一个 react 项目。

接着安装 reduxreact-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 操作
相关推荐
undefined&&懒洋洋7 分钟前
Web和UE5像素流送、通信教程
前端·ue5
大前端爱好者2 小时前
React 19 新特性详解
前端
随云6322 小时前
WebGL编程指南之着色器语言GLSL ES(入门GLSL ES这篇就够了)
前端·webgl
随云6322 小时前
WebGL编程指南之进入三维世界
前端·webgl
寻找09之夏3 小时前
【Vue3实战】:用导航守卫拦截未保存的编辑,提升用户体验
前端·vue.js
多多米10054 小时前
初学Vue(2)
前端·javascript·vue.js
柏箱4 小时前
PHP基本语法总结
开发语言·前端·html·php
新缸中之脑4 小时前
Llama 3.2 安卓手机安装教程
前端·人工智能·算法
hmz8564 小时前
最新网课搜题答案查询小程序源码/题库多接口微信小程序源码+自带流量主
前端·微信小程序·小程序
看到请催我学习4 小时前
内存缓存和硬盘缓存
开发语言·前端·javascript·vue.js·缓存·ecmascript