42、Redux数据存储API的高级应用

Redux数据存储API的高级应用

在Redux开发中,为了更好地管理数据存储和组件连接,我们可以使用一些高级特性,如Reducer增强器、数据存储中间件、数据存储增强器以及React - Redux的高级连接特性。下面将详细介绍这些内容。

1. Reducer增强器

Reducer增强器是一种函数,它接收一个或多个普通的reducer,并为数据存储添加额外的功能。Redux在使用Reducer增强器时并没有特殊的处理,因为增强后的结果看起来就像一个普通的reducer,可以正常传递给 createStore 方法。

例如,Redux内置的 combineReducers 函数就是一个Reducer增强器,它可以将多个reducer组合在一起,使模型和状态数据的reducer逻辑分离。

以下是一个自定义Reducer增强器的示例:

// customReducerEnhancer.js
import { initialData } from "./initialData";
export const STORE_RESET = "store_clear";
export const resetStore = () => ({ type: STORE_RESET });
export function customReducerEnhancer(originalReducer) {
    let intialState = null;
    return (storeData, action) => {
        if (action.type === STORE_RESET && initialData != null) {
            return intialState;
        } else {
            const result = originalReducer(storeData, action);
            if (intialState == null) {
                intialState = result;
            }
            return result;
        }
    }
}

这个 customReducerEnhancer 函数接收一个reducer作为参数,并返回一个新的reducer函数。它会记录数据存储的初始状态,当接收到 STORE_RESET 类型的action时,会返回初始状态,从而重置数据存储。

应用这个Reducer增强器的代码如下:

// index.js
import { createStore, combineReducers } from "redux";
import modelReducer from "./modelReducer";
import stateReducer from "./stateReducer";
import { customReducerEnhancer } from "./customReducerEnhancer";
const enhancedReducer = customReducerEnhancer(
    combineReducers(
        {
            modelData: modelReducer,
            stateData: stateReducer
        })
);
export default createStore(enhancedReducer);
export { saveProduct, saveSupplier, deleteProduct, deleteSupplier }
    from "./modelActionCreators";

StoreAccess 组件中使用 resetStore action creator来触发数据存储的重置:

// StoreAccess.js
import React, { Component } from "react";
import { resetStore } from "./customReducerEnhancer";
export class StoreAccess extends Component {
    constructor(props) {
        super(props);
        this.selectors = {
            product: (storeState) => storeState.modelData.products[0],
            state: (storeState) => storeState.stateData
        }
        this.state = this.selectData();
    }
    render() {
        return <React.Fragment>
            <div className="text-center">
                <button className="btn btn-primary m-1"
                    onClick={ this.dispatchAction }>
                        Dispatch Action
                </button>
            </div>
            <div className="bg-info">
                <pre className="text-white">
                    { JSON.stringify(this.state, null, 2) }
                </pre>
            </div>
        </React.Fragment>
    }
    dispatchAction = () => {
        this.props.store.dispatch(resetStore())
    }
    // ...other methods omitted for brevity...
}

当用户点击 Dispatch Action 按钮时,应用的状态和模型数据会被重置,任何更改都会被丢弃。

2. 数据存储中间件

Redux支持数据存储中间件,中间件是一种函数,它在action被传递给 dispatch 方法之后、到达reducer之前接收action,允许对action进行拦截、转换或其他处理。

常见的中间件用途包括支持执行异步任务的action,以及将action包装在函数中以便有条件地或在未来进行调度。

以下是一个自定义中间件的示例:

// multiActionMiddleware.js
export function multiActions({dispatch, getState}) {
    return function receiveNext(next) {
        return function processAction(action) {
            if (Array.isArray(action)) {
                action.forEach(a => next(a));
            } else {
                next(action);
            }
        }
    }
}

这个中间件会检查action是否为数组,如果是数组,则将数组中的每个对象依次传递给下一个中间件组件进行处理。

使用箭头函数可以更简洁地表达相同的功能:

// multiActionMiddleware.js
export const multiActions = ({dispatch, getState}) => next => action => {
    if (Array.isArray(action)) {
        action.forEach(a => next(a));
    } else {
        next(action);
    }
}

注册中间件的代码如下:

// index.js
import { createStore, combineReducers, applyMiddleware } from "redux";
import modelReducer from "./modelReducer";
import stateReducer from "./stateReducer";
import { customReducerEnhancer } from "./customReducerEnhancer";
import { multiActions } from "./multiActionMiddleware";
const enhancedReducer = customReducerEnhancer(
    combineReducers(
        {
            modelData: modelReducer,
            stateData: stateReducer
        })
);
export default createStore(enhancedReducer, applyMiddleware(multiActions));
export { saveProduct, saveSupplier, deleteProduct, deleteSupplier }
    from "./modelActionCreators";

可以将多个中间件函数作为单独的参数传递给 applyMiddleware 函数,它会按照指定的顺序将它们链接在一起。

现在数据存储可以处理action数组,我们可以定义生成更复杂结果的action creator,使连接器组件的表达更简单。例如:

// multiActionCreators.js
import { PRODUCTS } from "./dataTypes";
import { saveProduct, saveSupplier } from "./modelActionCreators";
import { endEditing } from "./stateActions";
export const saveAndEndEditing = (data, dataType) =>
    [dataType === PRODUCTS ? saveProduct(data) : saveSupplier(data), endEditing()];

EditorConnector 组件中使用这个action creator:

// EditorConnector.js
import { connect } from "react-redux";
import { endEditing } from "./stateActions";
import { PRODUCTS, SUPPLIERS  } from "./dataTypes";
import { saveAndEndEditing } from "./multiActionCreators";
export const EditorConnector = (dataType, presentationComponent) => {
    const mapStateToProps = (storeData) => ({
        editing: storeData.stateData.editing
            && storeData.stateData.selectedType === dataType,
        product: (storeData.modelData[PRODUCTS]
            .find(p => p.id === storeData.stateData.selectedId)) || {},
        supplier:(storeData.modelData[SUPPLIERS]
            .find(s => s.id === storeData.stateData.selectedId)) || {}
    })
    const mapDispatchToProps = {
        cancelCallback: endEditing,
        saveCallback: (data) => saveAndEndEditing(data, dataType)
    }
    return connect(mapStateToProps, mapDispatchToProps)(presentationComponent);
}
3. 数据存储增强器

大多数项目可能不需要修改数据存储的行为,如果需要,中间件功能通常就足够了。但如果中间件无法提供足够的灵活性,可以使用增强器函数。

增强器函数负责创建数据存储对象,并可以为标准方法提供包装器或定义新方法。例如,之前使用的 applyMiddleware 函数就是一个增强器函数,它会替换数据存储的 dispatch 方法,使action在到达reducer之前通过中间件链。

以下是一个添加异步调度action方法的增强器示例:

// asyncEnhancer.js
export function asyncEnhancer(delay) {
    return function(createStoreFunction) {
        return function(...args) {
            const store = createStoreFunction(...args);
            return {
                ...store,
                dispatchAsync: (action) => new Promise((resolve, reject) => {
                    setTimeout(() => {
                        store.dispatch(action);
                        resolve();
                    }, delay);
                })
            };
        }
    }
}

使用箭头函数更简洁的写法:

// asyncEnhancer.js
export const asyncEnhancer = delay => createStoreFunction => (...args) => {
    const store = createStoreFunction(...args);
    return {
        ...store,
        dispatchAsync: (action) => new Promise((resolve, reject) => {
            setTimeout(() => {
                store.dispatch(action);
                resolve();
            }, delay);
        })
    };
}

应用增强器的代码如下:

// index.js
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import modelReducer from "./modelReducer";
import stateReducer from "./stateReducer";
import { customReducerEnhancer } from "./customReducerEnhancer";
import { multiActions } from "./multiActionMiddleware";
import { asyncEnhancer } from "./asyncEnhancer";
const enhancedReducer = customReducerEnhancer(
    combineReducers(
        {
            modelData: modelReducer,
            stateData: stateReducer
        })
);
export default createStore(enhancedReducer,
    compose(applyMiddleware(multiActions), asyncEnhancer(2000)));
export { saveProduct, saveSupplier, deleteProduct, deleteSupplier }
    from "./modelActionCreators";

StoreAccess 组件中使用增强后的数据存储方法:

// StoreAccess.js
import React, { Component } from "react";
import { resetStore } from "./customReducerEnhancer";
export class StoreAccess extends Component {
    constructor(props) {
        super(props);
        this.selectors = {
            product: (storeState) => storeState.modelData.products[0],
            state: (storeState) => storeState.stateData
        }
        this.state = this.selectData();
        this.buttonRef = React.createRef();
    }
    render() {
        return <React.Fragment>
            <div className="text-center">
                <button className="btn btn-primary m-1" ref={ this.buttonRef }
                    onClick={ this.dispatchAction }>
                        Dispatch Action
                </button>
            </div>
            <div className="bg-info">
                <pre className="text-white">
                    { JSON.stringify(this.state, null, 2) }
                </pre>
            </div>
        </React.Fragment>
    }
    dispatchAction = () => {
        this.buttonRef.current.disabled = true;
        this.props.store.dispatchAsync(resetStore())
            .then(data => this.buttonRef.current.disabled = false);
    }
    // ...other methods omitted for brevity...
}

当用户点击按钮时,action会在两秒后被处理,组件在调度action时会收到一个Promise,action调度完成后Promise会被解决,从而使按钮再次可用。

4. React - Redux API的高级连接特性

在大多数项目中,使用React - Redux包来连接组件和数据存储更为简单。 connect 方法通常用于选择数据属性和函数属性。

connect 函数的第一个参数用于从数据存储中选择组件的数据属性。选择器函数通常定义为接收 getState 方法返回的值,并返回一个对象,其属性对应于组件的属性名。当数据存储发生变化时,选择器函数会被调用, connect 函数创建的高阶组件会使用 shouldComponentUpdate 生命周期方法来判断是否需要更新连接器组件。

选择器函数还可以接收第二个参数,用于接收父组件为连接器组件提供的属性,这样可以根据组件的属性来选择数据,并确保在组件属性或数据存储发生变化时重新评估选择器函数。

以下是一个使用额外参数的示例:

// TableConnector.js
import { connect } from "react-redux";
import { startEditingProduct, startEditingSupplier } from "./stateActions";
import { deleteProduct, deleteSupplier } from "./modelActionCreators";
import { PRODUCTS, SUPPLIERS } from "./dataTypes";
export const TableConnector = (dataType, presentationComponent) => {
    const mapStateToProps = (storeData, ownProps) => {
        if (!ownProps.needSuppliers) {
            return { products: storeData.modelData[PRODUCTS] };
        } else {
            return {
                suppliers: storeData.modelData[SUPPLIERS].map(supp => ({
                    ...supp,
                    products: supp.products.map(id =>
                        storeData.modelData[PRODUCTS]
                            .find(p => p.id === Number(id)) || id)
                            .map(val => val.name || val)
                }))
            }
        }
    }
    const mapDispatchToProps = {
        editCallback: dataType === PRODUCTS
            ? startEditingProduct : startEditingSupplier,
        deleteCallback: dataType === PRODUCTS ? deleteProduct : deleteSupplier
    }
    return connect(mapStateToProps, mapDispatchToProps)(presentationComponent);
}

在这个示例中,根据 needSuppliers 属性的值来决定映射哪些属性到数据存储。

通过上述这些高级特性,我们可以更灵活地管理Redux中的数据存储和组件连接,提高代码的可维护性和可扩展性。

操作步骤总结

Reducer增强器使用步骤
  1. 定义自定义Reducer增强器函数,如 customReducerEnhancer
  2. index.js 中使用 combineReducers 组合reducer,并将其作为参数传递给自定义Reducer增强器。
  3. 使用增强后的reducer创建数据存储。
  4. 在组件中使用action creator触发增强器的功能。
中间件使用步骤
  1. 定义中间件函数,如 multiActions
  2. 使用 applyMiddleware 函数将中间件应用到数据存储。
  3. 定义生成action数组的action creator,如 saveAndEndEditing
  4. 在组件中使用这些action creator。
数据存储增强器使用步骤
  1. 定义数据存储增强器函数,如 asyncEnhancer
  2. 使用 compose 函数组合多个增强器。
  3. 将组合后的增强器应用到数据存储。
  4. 在组件中使用增强后的数据存储方法。
React - Redux高级连接特性使用步骤
  1. connect 函数的选择器函数中使用额外参数接收组件属性。
  2. 根据组件属性决定映射哪些数据存储属性到组件属性。

流程图

graph TD;
    A[定义Reducer增强器] --> B[组合reducer并应用增强器];
    B --> C[创建数据存储];
    C --> D[组件使用action creator];
    E[定义中间件] --> F[应用中间件到数据存储];
    F --> G[定义action数组的action creator];
    G --> H[组件使用action creator];
    I[定义数据存储增强器] --> J[组合增强器];
    J --> K[应用增强器到数据存储];
    K --> L[组件使用增强后方法];
    M[定义选择器函数] --> N[使用额外参数选择数据];
    N --> O[组件使用连接功能];

表格

特性 作用 示例代码文件
Reducer增强器 为数据存储添加额外功能,如重置数据存储 customReducerEnhancer.js index.js StoreAccess.js
数据存储中间件 拦截、转换或处理action,支持异步任务等 multiActionMiddleware.js index.js multiActionCreators.js EditorConnector.js
数据存储增强器 修改数据存储行为,添加新方法 asyncEnhancer.js index.js StoreAccess.js
React - Redux高级连接特性 灵活选择数据存储属性到组件属性 TableConnector.js

Redux数据存储API的高级应用

5. 不同特性的对比与选择

在实际开发中,我们需要根据具体的需求来选择合适的Redux特性。下面通过一个表格来对比不同特性的适用场景和特点:
| 特性 | 适用场景 | 特点 |
| ---- | ---- | ---- |
| Reducer增强器 | 需要对数据存储进行整体功能扩展,如重置数据存储 | 可以在action处理前接收action,对action进行修改、拒绝或特殊处理 |
| 数据存储中间件 | 处理异步任务、批量处理action等 | 在action到达reducer之前进行拦截和转换,支持链式调用 |
| 数据存储增强器 | 中间件无法满足需求,需要对数据存储的标准方法进行包装或定义新方法 | 负责创建数据存储对象,提供更高级的定制功能 |
| React - Redux高级连接特性 | 灵活配置组件与数据存储的连接,根据组件属性选择数据 | 可以根据组件属性动态选择数据,减少不必要的更新 |

6. 实际项目中的应用建议

在实际项目中,我们可以按照以下步骤来应用这些高级特性:
1. 需求分析 :明确项目中是否有对数据存储功能扩展、异步处理、组件连接优化等需求。
2. 特性选择 :根据需求选择合适的特性,如需要重置数据存储可以选择Reducer增强器,处理异步任务可以选择数据存储中间件。
3. 代码实现 :按照前面介绍的操作步骤进行代码实现,注意代码的模块化和可维护性。
4. 测试与优化 :对实现的功能进行测试,确保其正常工作,并根据测试结果进行优化。

7. 常见问题及解决方案

在使用这些高级特性时,可能会遇到一些常见问题,以下是一些解决方案:
- 性能问题 :如果在使用中间件或增强器时出现性能问题,可以检查中间件或增强器的逻辑是否复杂,是否存在不必要的计算。可以考虑对代码进行优化,如使用缓存、减少不必要的循环等。
- 组件更新问题 :在使用React - Redux高级连接特性时,如果组件出现不必要的更新,可以检查选择器函数是否正确,是否根据组件属性动态选择数据。可以使用 shouldComponentUpdate 生命周期方法来控制组件的更新。
- 异步任务处理问题 :在使用数据存储中间件处理异步任务时,如果出现异步任务无法正常执行或顺序混乱的问题,可以检查中间件的逻辑是否正确,是否正确处理了异步操作。可以使用Promise或async/await来处理异步任务。

8. 总结与展望

通过使用Redux的高级特性,如Reducer增强器、数据存储中间件、数据存储增强器和React - Redux高级连接特性,我们可以更灵活地管理数据存储和组件连接,提高代码的可维护性和可扩展性。

在未来的开发中,随着项目的不断复杂,这些高级特性将发挥更大的作用。同时,我们也可以关注Redux生态系统的发展,学习和使用更多的优秀工具和库,进一步提升开发效率和代码质量。

流程图

graph LR;
    A[需求分析] --> B[特性选择];
    B --> C[代码实现];
    C --> D[测试与优化];
    D --> E[项目上线];
    F[性能问题] --> G[代码优化];
    H[组件更新问题] --> I[检查选择器函数];
    J[异步任务处理问题] --> K[检查中间件逻辑];

表格

问题 解决方案
性能问题 检查中间件或增强器逻辑,使用缓存、减少不必要的循环
组件更新问题 检查选择器函数,使用 shouldComponentUpdate 控制更新
异步任务处理问题 检查中间件逻辑,使用Promise或async/await处理异步任务

通过以上内容,我们对Redux的高级特性有了更深入的了解,希望这些知识能帮助你在实际项目中更好地应用Redux。

内容概要:本文档围绕六自由度机械臂的ANN人工神经网络设计展开,涵盖正向与逆向运动学求解、正向动力学控制,并采用拉格朗日-欧拉法推导逆向动力学方程,所有内容均通过Matlab代码实现。同时结合RRT路径规划与B样条优化技术,提升机械臂运动轨迹的合理性与平滑性。文中还涉及多种先进算法与仿真技术的应用,如状态估计中的UKF、AUKF、EKF等滤波方法,以及PINN、INN、CNN-LSTM等神经网络模型在工程问题中的建模与求解,展示了Matlab在机器人控制、智能算法与系统仿真中的强大能力。; 适合人群:具备一定Ma六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)tlab编程基础,从事机器人控制、自动化、智能制造、人工智能等相关领域的科研人员及研究生;熟悉运动学、动力学建模或对神经网络在控制系统中应用感兴趣的工程技术人员。; 使用场景及目标:①实现六自由度机械臂的精确运动学与动力学建模;②利用人工神经网络解决传统解析方法难以处理的非线性控制问题;③结合路径规划与轨迹优化提升机械臂作业效率;④掌握基于Matlab的状态估计、数据融合与智能算法仿真方法; 阅读建议:建议结合提供的Matlab代码进行实践操作,重点理解运动学建模与神经网络控制的设计流程,关注算法实现细节与仿真结果分析,同时参考文中提及的多种优化与估计方法拓展研究思路。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值