HenrikJoreteg / redux-bundler

Compose a Redux store out of smaller bundles of functionality.
https://reduxbundler.com
583 stars 46 forks source link

Need a way to pass props to selectors #62

Open learnyst opened 4 years ago

learnyst commented 4 years ago

To implement a eCommerce like app using redux-bundler in react-native we need a way to pass props to selectors.

Suppose the eCommerce site will have the list of items in first screen. User will select the item to buy and when he select a item user will navigate to itemDetails screen. In item details screen we will display itemDetails and also the list of recommended items. when the user click a recommended item again we will mount a itemDetails screen which will have the itemDetails.

Since this is react-native project we will use the stack navigator for this scenario. In this case 3 screens will be active itemList->itemDetails(Selected item from item list)->itemDetails->(Selected recommended item)

Using redux bundler pattern, we will have selector to get the list of items which is used in itemList screen. We will have another selector getItemDetails which is used in itemDetails screen. getItemDetails will use another selector getCurrentItemId. currentItemId will be set in reducer when the navigation change happens.

Now the issue is: we have 2 itemDetails screens mounted but we have only one currentItemId. When the user goes from one itemDetails screen to another currentItemId will change which cause both itemDetails to rerender and also both will have same data. Also this will lead to crash of the app since we are changing the currentItemId which details are still used by previous screen (Reason for crash is: Suppose the itemDetails screen has a list and each item in list is connected to store using selectors. Now if currentItemId is changed, the new item will not have the same list properties and list IDs, and the corresponding selector will return invalid data which will lead to crash)

So there are 2 issues now:

  1. CurrentItemId is changed, so both itemDetails will have same data.
  2. Crashes in the app if the new list properties of itemdetails are different

Issue 1 can be solved by maintaining 2 itemIds in the reducer like currentItemId and currentRecommendedItemId. But the recommended itemDetails screen can mount another screen. Issue-2 can be solved by adding multiple checks in the component which is dirty and error prone.

Generally this problem is solved by using mapStateToProps which will have ownProps and based on ownProps we can select the corresponding details .

So we need a way to pass props to the selectors. selector should return the data based on ownprops. Also itemDetails screen has reactors and each screen should have its copy of reactor.

We need to dd this pattern in redux-bundler. It will be very helpful for recact-native apps.

learnyst commented 4 years ago

@HenrikJoreteg this issue is similar as #51 #54 . We need a better way to solve this issue

HenrikJoreteg commented 4 years ago

Hi there 😊 I'm afraid I disagree a bit with the need for this. If you model the state of your open screens in a "screens" bundle then you can track which windows have which IDs whether you had one, two, or 500. Which ones are active, etc. And you never have to switch the product ID of a given screen. The "own props" you want to pass to a selector are just state like anything else, but you're now externalizing it. So instead of it being represented I'm redux those props would live outside your centralized redux state.

I think perhaps something that would help you is to write a selector that models the screens and their associated IDs.

learnyst commented 4 years ago

@HenrikJoreteg thanks for replying.

Screens bundle looks like a good idea. But I am not able to think how to write the screens bundle. Consider we have 2 itemDetails screens open. Both will have its item ID. In bundles we will have the selectors like below:

selectCurrentItemId = state => state.currentIemId selectCurrentItemDetails = createSelector('selectCurrentItemId', (curItemId)=> {return state.items[curItemId]}),

Since we have 2 screens open, selectCurrentItemId should somehow take the itemId of the corresponding screen which is accessing the selectors to get the details. How can we do this using screens bundle?

In screens bundle we can have the list of open screens and its associated params. But how can the selector get the corresponding itemId from screen bundle? The link between the screen and its associated ID can be established using screens bundle. My issue is when the screen uses selector to get the data, the selector should get the itemId corresponding to screen and then return the details. How can we do this?

HenrikJoreteg commented 4 years ago

I'm not very familiar with React Native, or the stack navigator. But... I'm imagining something like:

selectItemScreens: createSelector(
  'selectScreens',
  'selectItemsKeyedById',
  (screens, items) => screens.map(screen => {
    return {
      item: items[screen.itemId],
      ...screen
    }
  })  
) 

Then instead of doing a single connected component you'd do something like:

export default connect(
  'selectItemScreens',
  ({ itemScreens }) => (
    <ScreenContainer>
       {itemScreens.map(screen => (
          <Screen {...screen}/>
        ))}
    </ScreenContainer>
  )
)