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

时间:2017-04-28 12:10:59

标签: reactjs redux redux-saga

[React-Redux]问题。

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

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

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

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

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

我会非常乐意以优雅的方式了解这个问题的正确解决方案。

或许我们在谈论react-redux-sagas应用时,我们只是在思考错误的方法。

3 个答案:

答案 0 :(得分:3)

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

在使用编辑器的代码中,我给每个编辑器一个唯一的id。 E.g。

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);

如果要扩展此功能以在多个应用中使用,则需要导出组件,减速器和传真。有关工作示例,请查看https://github.com/woltapp/redux-autoloader甚至http://redux-form.com

答案 1 :(得分:0)

如果我理解您的问题,您可以实施mapStateToProps,就像它收到您需要的州的一部分并称之为mapStateToYourComponentProps,并且实际上mapStateToProps致电mapStateToYourComponentProps并将其传递给州的适当部分

答案 2 :(得分:0)

如果你有空闲时间,请尝试我刚刚写的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; } } });
    }

它让您拥有更简单的减速器。此外,没有更多的嵌套选择器功能或过滤器,这是非常昂贵的操作。将所有逻辑放在同一个地方会很棒。

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

    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);

如果您想获得完整或有效的列表,也很容易获得。 更多示例,请参阅示例代码=&gt; https://github.com/jeffnian88/redux-livequery-todos-example