React-Redux 连接:使用 mapStatetoProps 仅注入商店的组件部分

React-Redux connect: Use mapStatetoProps to inject only component part of store

[React-Redux] 问题。

我希望在任何应用程序或应用程序商店的任何级别中使用可重复使用的封装组件。

当使用 'mapStatetoProps' 然后制作组件容器(将状态作为 props 注入组件)时,您总是会收到整个商店。如果您想动态地或在其他项目中重用组件,这可能会很痛苦。

问题是,如果您使用相同的商店条目,但您想使用与封装模块相同的组件,它们将共享相同的数据。

而且,当您封装组件并重用它们并且它们深深嵌套在商店中时,您最终需要知道它们在哪里。

一个可能的丑陋解决方案是实现一个脚本,遍历 mapStateToProps 中的状态,直到找到与特定名称匹配的键。这里的问题是确保您要使用的状态字段是唯一的。

我很高兴知道以优雅的方式解决此问题的任何适当方法。

或者我们在谈论 react-redux-sagas 应用程序时可能只是想错了方向。

如果我正确理解了您的问题,您可以实施 mapStateToProps,就好像它接收到您需要的状态部分并调用它,比如说,mapStateToYourComponentProps,实际上 mapStateToProps您只需调用 mapStateToYourComponentProps 并将状态

的适当部分传递给它

为了这个例子,我将讨论一个可重用的编辑器组件,它编辑文档并将它们提交到服务器。

在使用编辑器的代码中,我给每个编辑器一个唯一的 ID。例如

const Comment = (props) => {
  return <div>
    <h3>Add new comment</h3>
    <Editor editorId={`new-comment-${props.commentId}`} />
  </div>
}

在 redux 状态下,我有一个 subreducer 编辑器,其中的对象由 editorId 键控,所以 redux 状态类似于:

{
  otherStuff: {...},
  editor: {
    "new-comment-123": { isActive: true, text: "Hello there" },
    "new-comment-456": { isActive: false, text: "" },
    ...
  },
  ...
}

然后在编辑器中 mapStateToProps 我使用选择器获取正确实例的数据:

const mapStateToProps = (state, ownProps) => {
  return {
    isActive: selectors.isActive(state, ownProps.editorId),
    text: selectors.text(state, ownProps.editorId)
  }
}

选择器内置 reselect 风格,手动或实际使用重新选择。示例:

// Manual code
export const getEditor = (state, editorId) => state.editor[editorId] || {};
export const isActive = (state, editorId) => getEditor(state, editorId).
export const text = (state, editorId) => getEditor(state, editorId).text;

// Same in reselect
import { createSelector } from 'reselect'

export const getEditor = (state, editorId) => state.editor[editorId] || {};
export const isActive = createSelector([getEditor], (editorData) => editorData.isActive);
export const text = createSelector([getEditor], (editorData) => editorData.text);

如果你想扩展它以在多个应用程序中使用,你需要导出你的组件、reducer 和 sagas。有关工作示例,请查看 https://github.com/woltapp/redux-autoloader or even http://redux-form.com

我找到了一种使组件完全独立于应用程序内的状态和层次结构的方法。

基本上,每个组件都必须公开一个方法来设置状态内的路径。然后你必须在使用它之前导入它时初始化它。你也可以用另一种方式实现它,这样你就可以将它作为道具内联接收。

它使用重新选择来建立选择。

每个组件都知道其在状态中的键的名称。

根组件会导入其他组件,它会调用每一个传入根组件路径的setPath方法

然后每个组件将调用每个子组件的setPath,传递它们在状态中的位置。 "Each parent will init their children"

所以每个组件都会根据命名在store中设置一个路径"parent path + local path (component key name in the store)"。

这样,您将使用来自重新选择的 'createSelector' 方法定义嵌套路由,如下所示:['rootKey','subComponent1Key','subsubComponent1Key]。

至此,您已完成商店隔离。 Redux 操作只会改变所需的位,所以框架也涵盖了这部分。

它对我来说就像一个魅力,在我将其标记为好之前请告诉我它是否好。

如果你有空闲时间,试试我最近刚写的 npm 包 redux-livequery (https://www.npmjs.com/package/redux-livequery)。

还有另一种管理活动列表的方法。

    let selector0 = (state) => state.task.isComplete;
    let selector1 = (state) => state.task.taskList;
    this.unsub2 = rxQueryBasedOnObjectKeys([selector0, selector1], ['isActive', 'task'], (completeTaskList) => {
        // equal SQL =>
        // select * from isActive LEFT JOIN taskList on isActive.child_key == taskList.child_key
        console.log("got latest completeTaskList", completeTaskList);
        // you can do whatever you want here
        // ex: filter, reduce, map

        this.setState({ completeTaskList });
    }, 0);

在减速器中:

    case "MARK_ACTIVE_TASK": {
        let { id } = action.meta;
        return update(state, { isActive: { [id]: { $set: { active: Date.now() } } } });
    }
    case "UNMARK_ACTIVE_TASK": {
        let { id } = action.meta;
        return update(state, { isActive: { $apply: function (x) { let y = Object.assign({}, x); delete y[id]; return y; } } });
    }

它让你拥有更简单的reducer。此外,不再有嵌套的选择器函数或过滤器,这是非常昂贵的操作。将所有逻辑放在同一个地方会很棒。

而且它可以做更复杂的操作,比如如何获得完整和活跃的列表。

    let selector0 = (state) => state.task.isComplete;
    let selector1 = (state) => state.task.isActive;
    let selector2 = (state) => state.task.taskList;
    this.unsub3 = rxQueryInnerJoin([selector0, selector1, selector2], ['isComplete', 'isActive', 'task'], (completeAndActiveTaskList) => {
        // equal SQL =>
        // select * from isComplete INNER JOIN isActive on isComplete.child_key == isActive.child_key
        //                          INNER JOIN taskList on isActive.child_key == taskList.child_key
        console.log("got latest completeAndActiveTaskList", completeAndActiveTaskList);
        // you can do whatever you want here
        // ex: filter, reduce, map

        this.setState({ completeAndActiveTaskList });
    }, 0);

如果您想获得完整或活跃的列表,也很容易获得。 更多示例请参考示例代码=> https://github.com/jeffnian88/redux-livequery-todos-example