Skip to content
This repository has been archived by the owner on Jan 27, 2021. It is now read-only.

Discussion: Recommended API for user-defined modules #33

Closed
jcheroske opened this issue Jul 11, 2017 · 15 comments
Closed

Discussion: Recommended API for user-defined modules #33

jcheroske opened this issue Jul 11, 2017 · 15 comments
Labels

Comments

@jcheroske
Copy link

I stumbled upon this the other day:

http://antontelesh.github.io/architecture/2016/03/16/fractal-architecture.html

My main takeaway was that a fractal component should have an api that's something like:

export create = () => ({ view, reducer })

Extending the idea to include the subspace concept, it seems like a possible best practice to build modules might be to use a pattern like:

export const createComponent = id => // return subspaced component

export const createReducer = id => // return subspaced reducer

The great thing here is that the parent component and parent reducer are still in charge of the namespace id, but they know nothing of the namespacing implementation. In some ways, this is like a duck for fractal components. Thoughts?

@mpeyper
Copy link
Contributor

mpeyper commented Jul 11, 2017

@jcheroske I wish you could see the library we are looking to open source soon. It sounds a lot like what you're asking for.

I'll add some more details of the API tonight.

@jcheroske
Copy link
Author

That's exciting! I'm very curious now.

Tying together your comment about scoped parent->child actions with this thread, I think that a module should export the action creators that are meant to be called from outside the module as another creator function. Something like:

const createReset = id => // return scoped action creator

The API for a given module then becomes essentially a function that returns the reducer, component, and action creators, all of them scoped.

@mpeyper
Copy link
Contributor

mpeyper commented Jul 11, 2017

So I had a better read of the article, and our solution is a little bit more reacty and theoretical than theirs.

Imagine you have a redux connected component

const MyComponent = ({ value, setValue } ) => <button onClick={setValue}>{value}</button>

const mapStateToProps = (state) => ({ value: state })
const mapDispatchToProps = (dispatch) => ({ setValue: () => dispatch(setValue("something else") })

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)

And you have a reducer for this component

export default (state = "test", action) => {
    return action.type == SET_VALUE ? action.value : state
}

We have a HOC that lets you go

import reducer from './reducer'
import MyComponent from './MyComponent'

export default withReducer(reducer, "value")(MyComponent)

Then in the parent you just mount it, and it injects a reducer with key value and namespaced to "value" and wraps the component in a subspace that maps to state.value and is namespaced with "value".

import MyComponent from 'my-component' // we generally have them as seperate npm packages

const Parent = () => <MyComponent />

And this works fine, but obviously there is an issue here for reusability. What if we wanted 2 instances of it on the same page? What if another component also uses "value" as it identifier?

No fear... The export also has a function to create unique instances of the component

import MyComponent from 'my-component'

const MyComponent1 = MyComponent.createInstance("value1")
const MyComponent2 = MyComponent.createInstance("value2")

const Parent = () => (
    <div>
        <MyComponent1 />
        <MyComponent2 />
    <div>

And that's the gist of it.

@jcheroske
Copy link
Author

That's amazing! I've always wired up my reducers manually. Seeing this is really starting to change my thinking. I keep coming back to this issue of how to control child components from the parent. The way your code looks, the children are so encapsulated, and reveal nothing about their redux nature, that exposing actions on the children almost seems a shame. Treating them as nothing but ordinary react components seems like the ideal.

Continuing our conversation on reseting a child that we started on #30, if you didn't have the ability to dispatch actions on the children, but only had normal parent->child patterns available (http://andrewhfarmer.com/component-communication/ & gaearon's comment at https://www.bountysource.com/issues/30234335-use-hoist-non-react-methods-instead-of-hoist-non-react-statics), what strategy would you use to reset a child from a parent's saga? You're in redux side-effect land, firing actions left and right. What's the clean way to manipulate that child?

@jcheroske
Copy link
Author

@mpeyper, any chance that lib could be open sourced?

@mpeyper
Copy link
Contributor

mpeyper commented Jul 12, 2017

@jcheroske, a very good chance... We literally just need to name it (the nature and scope of the library changed a lot from the original proof of concept, but unlike subspace, a name did not naturally emerge).

If you can think of a suitable name from looking at the API above, I'd love to hear it! :)

@jcheroske
Copy link
Author

jcheroske commented Jul 12, 2017

I like the namerefract for these redux namespace libs, but it's taken on npm, albeit by a lib that only got 124 dl last month. Perhaps you could convince the maintainer to give up the name?

This HOC is really more of a reducer injector and remover. reject? Lolz.

Now a package that would do action and state namespacing on Components, reducers, sagas, epics and logics, as well as injection and removal of reducers, sagas, epics and logics, would be a thing of beauty. To provide all the tools, as well as best practices, for creating fractal components, such that the end result would be a totally encapsulated Component with a normal React API would be a most welcome addition to the redux ecosystem.

@mpeyper
Copy link
Contributor

mpeyper commented Jul 12, 2017

npm dl counts are not a reliable indicator or use. Every time you push a new version you get a surge of downloads from all the various mirrors, and if anyone uses one of the mirrors or an internal npm registry that caches (like we do) it lowers the true download count. I can guarantee redux-subspace get more downloads a month than npm downloads as there would be dozens, even hundreds, a day just from IOOF.

After #18 is done, redux-subspace will be able to do Components, reducers, thunks and sagas. I plan to investigate redux-promise and redux-observable next as I believe these are the next most widely used side effect libraries. redux-logic is now on my radar so I will keep an eye on it as a future candidate for support.

You are also welcome to submit PRs for any middleware (or feature) you want. The new package structure proposed in #18 should make having other middleware support a little easier too (form within this repo or others).

@jcheroske
Copy link
Author

jcheroske commented Jul 12, 2017

Would you consider adding the withReducer HOC to redux-subspace?

When using this lib with sagas, what's the procedure? Do I install the saga once and then it will run for all instances of the subspaced component, or does the saga get installed with every instantiation of the component?

@mpeyper
Copy link
Contributor

mpeyper commented Jul 12, 2017

withReducer relies on a dynamic reducer solution that currently live within the same package as the HOC. I'd sooner it come under the subspace banner, as it relies quite heavily on redux-subsapce too, but as a new package (from the #18 proposition). If the dynamic reducers solution part of it was redux-dynamic-subspace (for example), then I would be comfortable to include withReducer in react-redux-subspace.

I might suggest this to our group and see what they think.

@jcheroske
Copy link
Author

Curious if you wouldn't mind publishing the code for your reducer-injector gizmo? We need something like that badly!

@vivian-farrell
Copy link
Contributor

Hi @jcheroske, we're going to look at publishing it in a separate library very soon (coming days). Stay tuned.

@jcheroske
Copy link
Author

That is fantastic news! Thank you for all your hard work.

@mpeyper
Copy link
Contributor

mpeyper commented Sep 29, 2017

@jcheroske it's up now! https://github.com/ioof-holdings/redux-dynamic-reducer

@mpeyper
Copy link
Contributor

mpeyper commented Oct 1, 2017

I'm going to close this off now as the discussion hasn't been progressing and I was only really keeping it open to remind myself that redux-dynamic-reducer hadn't been open sourced yet... but it has now.

@mpeyper mpeyper closed this as completed Oct 1, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

3 participants