Skip to content

connect's storeSubscription prop propagation when custom store is provided #942

Closed
@HeberLZ

Description

@HeberLZ

redux: 4.0.0
react-redux: 5.0.7
description: (updated to make more sense to ppl arriving late to the issue)

So here is the contrived example, hopefully it's simple enough.

Basically what happens is that connect when provided a store property will create a storeSubscription and propagate it as a prop downwards, which means that if we have two HoC's with custom store, one wrapping another, the second one will try to use the storeSubscription from the first one even though it's creating its own one too. This results in actions fired by the second HoC not propagating changes until an action on the first HoC happens.

I do know that this is not a common use-case and that the tool is actually intended to be used with Provider, where this behaviour does not happen because the storeSubscription does not get propagated as a prop downward, but due to the nature of the projects I'm working on I'm encountering this issue/non-issue. I already have a workaround which is to instead of returning the connect hoc directly, return a wrapper on top of the connect hoc which discards both storeSubscription input prop and output propagated props.

Mainly i'd like to know if it is a bug or if this is the intended behaviour of connect, and what's the reasoning behind it on the latter as it might make sense to work like that due to a design decision.

https://codesandbox.io/s/qlk98486n9

index.js

import React from "react";
import { render } from "react-dom";
import { compose, mapProps } from "recompose";

import createPlugin from "./createPlugin";

const { HoC: plugin1HoC, action: plugin1Action } = createPlugin(
  "attributeFromHoC1"
);
const { HoC: plugin2HoC, action: plugin2Action } = createPlugin(
  "attributeFromHoC2"
);

const NestedPluginsComponent = compose(plugin1HoC, plugin2HoC)(props => (
  <div>
    <h2>props: {Object.keys(props).join(", ")}</h2>
    <div>attributeFromHoC1: {props.attributeFromHoC1}</div>
    <button onClick={plugin1Action}>plugin1Action</button>
    <div>attributeFromHoC2: {props.attributeFromHoC2}</div>
    <button onClick={plugin2Action}>plugin2Action</button>
  </div>
));

const App = () => (
  <div>
    <NestedPluginsComponent />
  </div>
);

render(<App />, document.getElementById("root"));

createPlugin.jsx

import React from "react";
import { createStore } from "redux";
import { connect } from "react-redux";
import { compose, withProps } from "recompose";

export default function createPluginHoC(name) {
  const store = createStore(
    (s, a) =>
      a.type === "randomize"
        ? { [name]: Math.floor(Math.random() * 100 + 1) }
        : s,
    {}
  );
  return {
    HoC: compose(withProps({ store }), connect(s => s)),
    action: () => store.dispatch({ type: "randomize" })
  };
}

https://github.com/reactjs/react-redux/blob/57128d5a20d15f43513acd13251465966426d956/src/components/connectAdvanced.js#L199

To give some context, I'm currently working on autonomous embedded apps and plugins with custom stores that are used across multiple apps.

Is this an expected behaviour? should this be documented in that case? should this props not be propagated? or should the storeSubscription prop be ignored when the store property is provided?

Cheers!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions