Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide redux store for rendered components #195

Closed
bogdan-stefan-hs opened this issue Aug 26, 2016 · 4 comments
Closed

Provide redux store for rendered components #195

bogdan-stefan-hs opened this issue Aug 26, 2016 · 4 comments

Comments

@bogdan-stefan-hs
Copy link
Contributor

Need

As a user
I want to be able to load components/fixtures that need a Redux store
So that I can preview them.

Deliverables

Fixtures with state residing in a redux store do not throw an error on selection, and load normally.

Solution

  • Receive a reduxStore prop in CP.
  • On mount, create a Redux store, cloning the state from reduxStore prop.
  • Wrap the rendered component in a <Provider> component, with the initially created store.
  • On fixture change, reset the store to the initial state, then merge the fixture's reduxStore data in it, if it provides one.

That way, a store is provided for components belonging to Redux-enabled apps.

@bogdan-stefan-hs
Copy link
Contributor Author

I've read the discussion on this issue, which is somehow related to this, and I agree fully logging Flux/Redux actions is a little too specific for a general purpose tool.

However, this issue is only about being able to render a component storing its state higher up, in a Redux store. Actions dispatched by the component are simply ignored.

Redux has become pretty popular these days, and I believe it'll be a nice addition to react-cosmos.

@ovidiuch
Copy link
Member

Redux has become pretty popular these days, and I believe it'll be a nice addition to react-cosmos.

Totally agree. It's imperative Cosmos starts working nicely with things like Redux and context in general, in order to cover all real life scenarios of React components.

Not that Redux is not big enough to be embedded in the Cosmos by default, but I think we can build something more generic that solves the Redux use case and many others. Composable middlewares (I kinda like the word proxies more because it's shorter) common in other projects as well, like Redux. Here's what I have in mind:

CP receives a new prop called proxies. When CP renders a component, instead of rendering it directly it composes these proxy, with the loaded component at the end of the chain. Pseudo example:

const renderPreview = (proxies, proxyIndex, props) => {
  if (!proxies[renderIndex]) {
    return loadChild('preview', props);
  } else {
    const proxyComponent = proxies[proxyIndex];
    return React.createElement(proxyComponent, assign({}, props, {
      children: renderProxy(proxies, proxyIndex + 1, props)
    }));
  } 
}

Proxy components need to follow a single strict rule: Always render this.props.children and sent it its props. Here's are two simple examples:

// Adding markup around loaded component
const ReactCosmosDumbProxy = () => (
  <div>
    <p>I am dumb. Everything is dumb.</p>
    {this.props.children}
  </div>
);

// Altering fixture props
const ReactCosmosDumbProxy = (props) =>
  React.createElement(this.props.children, assign({}, props, {
    itR: 'dumb'
  }));

In the same format, you'd create a ReduxProvider that looks at props.store, creates the necessary context and passes it down to the loaded component (or the next proxy in line, for all it cares or knows.) Then we could publish packages like react-cosmos-redux-proxy for other to simply use like this:

// ... CP props
proxies: [
  require('react-cosmos-redux-proxy')
]

Or these proxies could be functions that generate the classes, based on a set of options. E.g.

// ... CP props
proxies: [
  require('react-cosmos-redux-proxy')({
    storeFixtureKey: '__reduxStore'
  });
]

I'm riffing here and I'm sure I overlooked some details, but I think the concept is powerful. What do you think?

@bogdan-stefan-hs
Copy link
Contributor Author

bogdan-stefan-hs commented Aug 29, 2016

I like the idea, I really love the flexibility of it. It's kind of like a plugin system, I guess.
It shouldn't be too hard to implement, either.

The only question I have is: how would you validate that a proxy renders the children? And what to do if it doesn't?
I'm thinking of having a placeholder that simply calls loadChild, and replace every 'bad' proxy in the list with that placeholder. Does it make sense?

Anyway, let's leave this issue open till i finish merging what I've already done, and I'll start working on this afterwards.

@ovidiuch
Copy link
Member

The only question I have is: how would you validate that a proxy renders the children? And what to do if it doesn't?
I'm thinking of having a placeholder that simply calls loadChild, and replace every 'bad' proxy in the list with that placeholder. Does it make sense?

Fair point, but I wouldn't worry about this at this stage. So far we only have one in the making :). We'll see if this plugin system gets traction and more proxies are created. You could log something like "Rendering stopped at react-cosmos-redux-proxy. Try removing it..."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants