-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
Allow for passing of action creators through Connector
and @connect
decorator
#86
Conversation
Connector
and @connect
decoratorConnector
and @connect
decorator
I like to have less boilerplate, but here's what I don't like about this API:
I can live with the first, but the second one is a red flag to me. If we're breaking This is also a problem with the current API and I agree it needs fixing. I just want to add first-class action creator binding support if it also fixes the |
One way to work around the
|
@gaearon Yes, I think that's the way to go. |
You can try exploring this API: @connect((state, bindActionCreators) => ({
counter: state.counter,
...bindActionCreators(CounterActions)
}))
export default class Counter {
render() {
}
} function select(state, bindActionCreators) {
return {
todos: state.todos,
actions: bindActionCreators(TodoActions)
};
}
export default class TodoApp {
render() {
return (
<Connector select={select}>
{this.renderChild}
</Connector>
);
}
renderChild({ todos, actions }) {
return (
<div>
<AddTodo {...actions} />
<TodoList todos={todos} {...actions} />
</div>
);
}
} You'll need to figure out some way of memoizing the bound functions though, so that if the |
What I like about What I don't like: “smart” memoization logic it would need to be efficient. I'd rather have // I wish I could make this fast
function select(state, dispatch) {
return {
todos: state.todos,
actions: bindActionCreators(TodoActions, dispatch)
};
} |
Also, as for my last suggestion—it's actually not much better than what we have now already. |
@@ -62,12 +68,27 @@ export default function createConnector(React) { | |||
return { slice }; | |||
} | |||
|
|||
bindActionCreators(dispatch) { | |||
if (!this.props.actionCreators) { | |||
return {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a sane default is the current behavior: injecting just the dispatch
prop. Let's remove this early exit, and instead specify dispatch => ({ dispatch })
as the default prop value for actionCreators
.
What is the use case for It's easy to pick just what you want for it:
|
I was thinking of namespaced actions when I thought of import * as CounterActions from './CounterActions';
import * as TodoActions from './TodoActions';
<Connector actionCreators={(dispatch) => ({
counter: bindActionCreators(CounterActions, dispatch),
todo: bindActionCreators(TodoActions, dispatch)
}) /> Anyway, of course this suffers from that |
Were you referring to having the |
Both. I think burdening I'm starting to like your original suggestion, given that you add some memoization, and remove the function overload. I think that, instead of namespacing, it's better to merge the actions, and if there are conflicts, you can always assemble a custom object and rename the functions as you need. |
Talk to me a little bit about how hot loader works with decorators right now...it reinitializes the whole component on every change, am I right? |
Yeah, that's the problem with decorators. I'll solve it eventually with this plugin but for now I recommend using container components for that very reason. |
As I go through this memoization process...I'm noticing this potential problem: <Connector actionCreators={{ ...CounterActions, ...TodoActions }}>
{() => [things]}
</Connector> That's going to create a new object every It would require the user to implement storing these elsewhere...which is completely fine...I think we just need to be sure we mention this somewhere. |
I'd say it's likely that the developer would measure where const actionCreators = { ...CounterActions, ...TodoActions };
<Connector actionCreators={actionCreators}>
{() => [things]}
</Connector> I think we can write an “Optimizing” doc later, but it's too early at this point as we're still figuring out the API. |
(The same argument can be made for |
Fair enough :) |
Just pushed a change the saves the bound action creators and only updates them when passed action creators changed. I know you also mentioned making sure they get updated when the dispatch method changes, which if I'm not mistaken, only happens when the entire redux instance is re-created, am I right? When would that happen? Only in hot-reloading? |
Yeah, I think so. |
Great. Can I ask you to update the examples and README to show how this API makes Redux better? |
Absolutely. Was already working on it. |
Thanks! |
What about the case where a component only needs to fire actions, but doesn't care about stores? The default |
Perhaps |
But what would you specify in case you only want the actions? Here's another proposal: use a special component for binding actions. Decorator version@bind(CounterActions)
@connect(state => ({
counter: state.counter
}))
export default class CounterApp {
render() {
return (
<Counter {...this.props} />
);
}
} Container versionexport default class TodoApp {
render() {
return (
<Bind actionCreators={TodoActions}>{(actionCreators) =>
<Connect select={state => ({ todos: state.todos })}>{({ todos }) =>
<div>
<AddTodo {...actionCreators} />
<TodoList todos={todos} {...actionCreators} />
</div>
}</Connect>
}</Bind>
);
}
} It would do a single thing, it would not complicate the existing Thoughts? |
Don't forget the user can always create their own |
I think that we definitely need a way to allow a component only to dispatch actions but to not get notified by store changes. Of course it's very useful for us lazy people that we can just use What about if @connect({
select: (state) => {...},
actions: actionObject
}) The |
@gaearon the fact that state isn't set should be enough, shouldn't it? |
That would work, yeah. I'm just not very keep on binding the actions, as it introduces some overhead. But since that stuff is optional anyway... |
That's how it used to be but I really dig the simplicity of a single function parameter. I feel like having |
@gaearon fair enough. Maybe instead of |
I like the |
👍 to the separate decorators and components |
I like the
is good and clear. the render function in the `decorator' version:
is more familiar. |
To those of you who are saying not to bind the actions...why not? The overhead is muted by the fact that we're memoizing the bind operation unless 1) the actions change or 2) the redux instance changes. |
As far as the multiple decorator/component approach, I'm down with that. I think having the One problem that I've run into when using multiple decorators on a component is that if I need access to the ref of the component I'm decorating, many decorators makes that difficult to do (without touching internal APIs). So if we just keep adding decorators upon decorators (as awesome as they are)...it can break component-to-component communication (a good use case for this, before everyone tells me I'm an idiot and shouldn't access components this way...is animation, where an inner component knows how to tween itself, but the parent container component actually handles synchronizing the tweens). It's very possible this doesn't matter...and there may be a BETTER way to handle this type of use case...but just thought I'd bring it up. I can work later on the multiple decorator approach, if that's the direction we want to explore. |
I'd like other collaborators to express their thoughts here and give it some time to rest. |
thought I'd ping this to see if any of the other collabs have had time to review? I'm not particularly attached to my idea over anyone else's, but it would be cool to get something like the ideas presented merged before 1.0 |
I'll definitely consider this before 1.0. :-) |
I'm all for #86 (comment) |
I give my +1 to the decorator solution, could be really useful! |
I'd love to hear more proposals for the alternative to the current |
Here's a more radical variation on this, with a very similar API but slightly different prescribed usage. I'd appreciate your comments and ideas there. |
I'm closing this in favor of reduxjs/react-redux#1 (comment). |
This is done in https://github.com/gaearon/react-redux/releases/tag/v0.5.0. |
Wooooo :) |
A possible solution to #84