Code Monkey home page Code Monkey logo

redux-components's People

Contributors

wcjohnson avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

gitter-badger

redux-components's Issues

Action noise in composed components (conceptual)

Action Noise in Composed Components

redux-components enables and encourages designs where components are built up from simpler ones as sub-branches using SubtreeMixin. In practice we've found that this can leave one with subtrees that may be a few levels deep, whose leaves are just a bunch of ObjectStores.

This kind of design can lead to a single action creator on a high branch firing multiple action creators on a subbranch, and so on down the tree until you get a quite large sequence of primitive actions reducing over all the ObjectStore leaves simultaneously, thus tripping a lot of Redux store updates.

We have been doing several things internally to mitigate this phenomenon:

NB: Don't prematurely optimize! Make sure this is actually a problem for you before using these remedies. For many use cases, there won't be a noticeable impact.

  • Batching actions with redux-batched-actions
  • Batching updates to connected React components with redux-batched-subscribe
  • The old country doctor's remedy: "It hurts when I do this. -- So stop doing that!" For components where state gets very deep, or where it is valuable to have composite rather than primitive actions in Redux's history (e.g. undo/redo use cases), we are avoiding deeply nested composition of redux-components.

I don't particularly like that we have to resort to the country doctor remedy, so I'm looking for feedback here. Early days but my own instincts tell me we need something like redux-batched-actions that can be mixed in at the top of deep subtrees that will (somehow) automatically compose the actions.

ES6 Classes as component classes

Now that CoffeeScript 2.0 is available, and we're on the Babel toolchain, we can deliver proper support for ES6 classes by analogy with the react model. Something like:

class MyComponent extends ReduxComponent
  # construction
  constructor: -> super

  # reducer
  getReducer: -> (state={}, action) -> state

  # lifecycle
  componentWillMount: ->
  componentDidMount: ->
  componentWillUnmount: ->

Problems will arise (as they do with React) in things like magic-binding functions. We will also need an API for doing the magic we do with selectors and actionCreators right now.

Interoperabiliity between duplicate copies of redux-components library in a bundle

In large builds, multiple packages may depend on redux-components. This can cause duplicate copies to end up in a webpack bundle.

This, in turn, causes multiple instances of key objects like the ReduxComponent base class, which causes instanceof() to fail to properly detect ReduxComponents that come from another copy of the library.

The ultimate manifestation of this is cannot mount something that isn't an instance of ReduxComponent errors in dev invariant mode.

We should consider storing critical information on a global object, or perhaps using something like React 15's $$typeof symbol.

Dynamic "Map" component and reducer combinator

Currently the subtree mixin allows you to have a predetermined component structure, which remains static throughout the application lifetime. This directly maps onto the redux combineReducers function.

It would be possible to implement a new combinator, say combineReducersMap, which as well as delegating actions to sub-reducers, also implements ADD and REMOVE actions itself. These actions would allow dynamically changing the set of child components and reducers.

The sequence of actions would be:

  • ADD action received, with a key and component type
  • Child path calculated by combining parent path with key
  • Component of the specified type is mounted at the child path
  • State at the path is initialised either from data passed with action or from a default specified by the component
  • Add component's reducer to the set of child reducers
  • Return state

This could then be encapsulated inside a Map component, which implements add and remove action creators.

Unfortunately it would be difficult to do the same thing for a List type, since the way this is currently built, each component is aware of its full path, and so it would be difficult to update all of the paths. Maybe with a componentMove event or similar, it would be possible...

The motivation is to be able to dynamically change the layout of stores - for example, you might have allow logging into multiple accounts at the same time, like google does, in which case you can put the vast majority of your application state inside a component which gets instantiated once per logged-in account.

Hot-replacement of reducers

Split from #4

There's no way to do this without creating state that's not a part of the store, because fundamentally, a reducer is a function and a function can't be state.

However, as you pointed out, if the state that's not a part of the store is a pure function of the state that is, and we can guarantee it gets synced with the store, that should still be OK.

So here are my thoughts right now:

  • getReducer() is now passed the local state as an argument. When first mounting, this will be the initial state. So:
getReducer: (state) => (state,action) => nextState
  • A new action symbol, @@REPLACE_REDUCER, will be added.

  • The actual reducer produced by Redux Components internally, the one that really gets mounted to the state tree, will be a closure that has an additional layer of indirection, and when it gets the @@REPLACE_REDUCER action, it will hot swap the "real" reducer by calling getReducer().

Advantages:

  • DOES NOT require the root store to rebuild its reducer!

  • State, in toto, is still a pure function of Redux state. getReducer() is only receiving information that already is in the store.

  • This doesn't just enable the thing we're talking about here, but a huge range of behaviors where reducers can depend purely on state.

Disadvantages:

  • Appears to absolutely require impurity in the intermediate layer of reducer indirection. How do we respond to @@REPLACE_REDUCER purely?

  • Performance hit of one extra nested function call for each layer of Redux state tree depth. (Won't matter when JS finally implements proper tailcalls -- probably won't matter before that, even.)

Things that need to be tested intensively:

  • Store initialization and rehydration situations

  • TIME TRAVEL

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.