arqex / freezer

A tree data structure that emits events on updates, even if the modification is triggered by one of the leaves, making it easier to think in a reactive way.
MIT License
1.28k stars 56 forks source link

Best way to implement Provider / connect( ... ) for React components using freezer? #92

Closed richardanaya closed 7 years ago

richardanaya commented 7 years ago

Do any of you have any suggestions for projects or patterns to create a connect(...) for freezer?

arqex commented 7 years ago

Hey @richardanaya

Good question! Since freezer doesn't force you to organize your data in any way I am really interested in knowing how people access to it. I can explain what I do, and it works nice for me.

First, I use to refresh the full app when any change happens in the store, so I don't need to connect components to parts of the store, they will be always re-rendered. I found out that trying to render parts selectively when changes happen in a part of the store is an easy way of get out of sync with the store and makes your app exponentially more complex. It's easier to not to render the components using shouldComponentUpdate when the store part has not changed, taking advantage of the immutable data.

In my apps I organize the freezer's store by domains. So imagine that I have two entities users and cars, I would create two domains in my store like:

{ 
  usersDomain: { /* all the user data here */ },
  carsDomain: { /* all the car data here */ }
} 

So the challenge is making those domains easily accessible by certain components. For example an Users component that lists all our app users should access to the usersDomain often.

Currently in my apps I pass the store's state down from the root component to the children using props:

<Child store={ freezer.get() } />

And I create a getDomain function in thoshe children that access often to the same part of the store:

getDomain(){
  return this.props.store.userDomain;
}

Add this method to every children is not very beautiful :) So I understand that you miss something like connect. Creating a higher order component to inject the domain as a prop shouldn't be difficult:

import React from 'react';
import FreezerStore from 'path/to/your/FreezerStore';

export default function connect( Component, domains ) {
  return function ConnectedComponent( props ){
    var storeDomains = {};
    domains.forEach( d => {
      storeDomains[d] = FreezerStore.get()[ d + 'Domain' ];
    });

    return <Component { ...props } { ...storeDomains } />;
  }
}

This way we get a connect function that we can use to make easier the access to the domains, we can build the UsersAndCars component this way:

import React from 'react';
import connect from 'path/to/connect';

class UsersAndCars extends React.Component {
  render(){
    // here I can use this.props.users and this.props.cars
  }
}

export default connect( UsersAndCars, ['users', 'cars'] );

I have not tried the code above, I have just coded it on the fly, so maybe it's buggy.

I am very interested in your thoughts about the way of organizing the data and also problems you are having with structuring the store with freezer.

richardanaya commented 7 years ago

Thanks! I like this idea.

On Aug 4, 2016 4:33 AM, "arqex" notifications@github.com wrote:

Hey @richardanaya https://github.com/richardanaya

Good question! Since freezer doesn't force you to organize your data in any way I am really interested in knowing how people access to it. I can explain what I do, and it works nice for me.

First, I use to refresh the full app when any change happens in the store, so I don't need to connect components to parts of the store, they will be always re-rendered. I found out that trying to render parts selectively when changes happen in a part of the store is an easy way of get out of sync with the store and makes your app exponentially more complex. It's easier to not to render the components using shouldComponentUpdate when the store part has not changed, taking advantage of the immutable data.

In my apps I organize the freezer's store by domains. So imagine that I have two entities users and cars, I would create two domains in my store like:

{ usersDomain: { /* all the user data here / }, carsDomain: { / all the car data here */ } }

So the challenge is making those domains easily accessible by certain components. For example an Users component that lists all our app users should access to the usersDomain often.

Currently in my apps I pass the store's state down from the root component to the children using props:

<Child store={ freezer.get() } />

And I create a getDomain function in thoshe children that access often to the same part of the store:

getDomain(){ return this.props.store.userDomain; }

Add this method to every children is not very beautiful :) So I understand that you miss something like connect. Creating a higher order component to inject the domain as a prop shouldn't be difficult:

import React from 'react';import FreezerStore from 'path/to/your/FreezerStore'; export default function connect( Component, domains ) { return function ConnectedComponent( props ){ var storeDomains = {}; domains.forEach( d => { storeDomains[d] = FreezerStore.get()[ d + 'Domain' ]; });

return <Component { ...props } { ...storeDomains } />;

} }

This way we get a connect function that we can use to make easier the access to the domains, we can build the UsersAndCars component this way:

import React from 'react';import connect from 'path/to/connect'; class UsersAndCars extends React.Component { render(){ // here I can use this.props.users and this.props.cars } } export default connect( UsersAndCars, ['users', 'cars'] );

I have not tried the code above, I have just coded it on the fly, so maybe it's buggy.

I am very interested in your thoughts about the way of organizing the data and also problems you are having with structuring the store with freezer.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/arqex/freezer/issues/92#issuecomment-237502745, or mute the thread https://github.com/notifications/unsubscribe-auth/AAR8mtTUMUVCer7RMv0Up85bXoHv2OIkks5qcbHrgaJpZM4JcC_b .