tonyhb / redux-ui

Easy UI state management for react redux
636 stars 58 forks source link

Can't create reselect selector using redux-ui state #49

Closed pablen closed 8 years ago

pablen commented 8 years ago

I have a dumb component which shows a list of items and a text input that lets you filter the list by item name. I decorated the component with redux-ui in order to save the input value in redux-ui state and set default state and key.

Then I wanted to use a reselect selector in a container component connected to Redux store that let me pass a filtered array of item to the dumb component via props based on the input value, but I found that when mapStateToProps runs the selector for the first time redux-ui haven't already created the component key in the Store so I get undefined.

It's not clear for me from the documentarion how to accomplish such a thing or if I'm thinking it all wrong. Sorry if it's a very silly question!

pablen commented 8 years ago

I just noticed that my case is almost exactly the same that is shown in this example https://tonyhb.gitbooks.io/redux-without-profanity/content/ui_state.html

Although contactsSelector code is not shown, I assume that its implementation would need access to display and filter UI state of that component but I understand that both are undefined when mapStateToProps try to assign the value to the contacts prop when the component is being mounted. Am I right?

The only difference I spot is that I'm using the non-decorator API. Could it be that? Thanks in advance!

RockingRolli commented 8 years ago

@pabloen I hope you solved the problem by now. I case you did not and to everyone that stumbles upon this issue:

The examples happily use the @ui decorator (which already uses connect() from react-redux) and don't tell you an important detail.

For example, you have code that looks similar to this:

class Whatever extends React.Component {}

const mapStateToProps = (state, props) => {
  // your code here
};

function mapDispatchToProps(dispatch) {
  // your code here
}

export default connect(mapStateToProps, mapDispatchToProps)(Whatever)

Addind the @ui decorator will make things weird now. The ui-state is not yet properly loaded into the state. That is because the order of the connect function and the @ui decorator has to be in a specific order!

Fixing this is actually pretty easy:

Option 1 Using connect as a decorator after the ui decorator

@ui({})
@connect(mapStateToProps, mapDispatchToProps)
class Whatever extends React.Component {}

Option 2 Chaining function calls

class Whatever extends React.Component {}
ui(uiConfig)(connect(mapStateToProps, mapDispatchToProps)(ListContacts))

Conclusion This is a tricky situation an unwary programmer can get into, especially when you have existing code that you want to extend. That the calls have to be in a certain order somehow gives me a bad feeling. This should at least be reflected in the documentation.

pablen commented 8 years ago

Thanks for your dedicated answer 👍 I think I may have tried changing the decorators order before submiting the question, but can't be sure now. Gonna try again!