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

Discussion: handling derived data #47

Closed
gaearon opened this issue Jun 6, 2015 · 7 comments
Closed

Discussion: handling derived data #47

gaearon opened this issue Jun 6, 2015 · 7 comments

Comments

@gaearon
Copy link
Contributor

gaearon commented Jun 6, 2015

@matystl brings up a great point here:

If you have DRY state than this state is usually not best for ui. Derivated data in their essence are pure functions over multiple store data which returns this data combined somehow. So without any further attempt in component you can subscribe to multiple stores and feed their values into this pure function and use result of this in rendering. This is not enough if you want to reuse this in more than one component which are not is child-parent relationship(can be passed as props) or if you don't want to expose this dependency between stores inside rendering and have it outside. With little bit of effort this abstraction can be implemented that derivated data for components will look like store and components can reed them and listen on it. From dispacher point of view after he run action through stores he will recalculate derivated data and only after that will issue change events to component. For performace reason you can use imutable data and caching results of derivated functions.

AFAIK NuclearJS solves this with the concept of Getters.

I don't want to complicate Redux with first-class support for derived data, but it's nice to consider options. Ideally I want something like this as a plugin for Redux. (It could come with a custom Injector that binds to a specific “getter”.)

There's no implementation plans at this point, but I'd love to discuss this and see your ideas!

@leoasis
Copy link
Contributor

leoasis commented Jun 9, 2015

Can't this be already achieved with the select function in the Connector? We can just write the getters as plain functions that receive the state (or part of it). The dependency tracking here is not needed since we are shouldComponentUpdateing based on the equality of the slice returned by that select function.

The only missing piece would be caching the getters during the dispatch cycle, as Nuclear does. Here perhaps is where we can use what you're suggesting with the concept of Injector, @gaearon?

Or perhaps this last thing can be just plain old function memoization?

@aaronjensen
Copy link
Contributor

Has there been any more thought on this? This area is interesting to me as well. I'm also curious what injectors are, it seems like maybe that was an older concept in redux?

@gaearon
Copy link
Contributor Author

gaearon commented Jun 15, 2015

Injector was renamed to Connector.

I think the way to go here is to provide utilities for creating smart memoizing select functions. I don't want to dive deep into this, but if somebody wants to experiment with this, please go ahead! Ideally it should work similarly to getters in NuclearJS and keep the current select API. (Might be a non-core createGetter function that returns a select-like function.)

@speedskater
Copy link

@gaearon After your suggestion in this gist https://gist.github.com/gaearon/d77ca812015c0356654f about combining stores/reducers we decided to use selectors to derive data from one or multiple stores/reducers. Due to performance considerations we drafted an initial selector function which can be used to create slectors and memoize the results. Below is the initial draft, which is applied to the example of todos an their derived count.

In the next days we will try to smooth out the rough edges and provide the selector create function and examples if this sounds interesting to you.

selector = (...keys, transformationFunction=_.identity) => {
    let lastParams = {};
    let lastResult = null
    return (state) => {
        if(!lastResult || _.find(keys, (key) => lastParams[key] != state[key] ) {
            lastParams = _.pick(subState, keys);
            lastResult = transformationFunction(lastParams);
        }
        return lastResult;
    }
}

An example module providing selectors related to the todos store/reducer would look like this:

export let todoSelector = selector('todos');
export let todoCountSelector = selector('todos', { todos } => {
    return {
            count: todos.length
        };
});

@gaearon
Copy link
Contributor Author

gaearon commented Jun 22, 2015

Great! Have you considered a composable API similar to NuclearJS's getters? I think they really nailed it.

@speedskater
Copy link

Created Proposal for selectors: #169

@gaearon
Copy link
Contributor Author

gaearon commented Jul 6, 2015

This is now being solved outside Redux: https://github.com/faassen/reselect

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

4 participants