frintjs / frint

Modular JavaScript framework for building scalable and reactive applications
https://frint.js.org/
MIT License
755 stars 34 forks source link

Proposal: frint-store-react #384

Closed fahad19 closed 6 years ago

fahad19 commented 6 years ago

(Intended to be done outside of this repository, after #378 is done)

Currently

To connect our frint-store's actions/state to components, we use our observe HoC like this:

// components/MyComponent.js
import React from 'react';
import { observe, streamProps } from 'frint-store';

import { 
  incrementCounter, 
  decrementCounter 
} from '../actions/counter.js';

const MyComponent(props) {
  // props has: `increment()`, `decrement()`, and `counter`
  return <div></div>;
}

export default observe(function (app) {
  const store = app.get('store');

  return streamProps()
    .set(
      store.getState$(),
      state => ({ counter: state.counter.value })
    )
    .setDispatch({
      increment: incrementCounter,
      decrement: decrementCounter,
   }, store)
   .get$();
})(MyComponent);

Proposal

To make it easier for developers, we can have a connect HoC (similar to that found in react-redux).

Example usage:

import { connect } from 'frint-store-react';

import {
  incrementCounter,
  decrementCounter
} from '../actions/counter';

function MyComponent(props) {
  // JSX
}

function mapStateToProps(state) {
  return {
    counter: state.counter.value,
  };
}

const dispatchableActions = {
  increment: incrementCounter,
  decrement: decrementCounter,
};

export default connect(
  mapStateToProps, 
  dispatchableActions
)(MyComponent);

Implementation

The code for connect HoC can be something like this:

// frint-store-react/connect.js
import { observe, streamProps } from 'frint-react';

export default function connect(mapStateToProps, mapDispatchToProps) {
  return function (Component) {
    return observe(function (app) {
      const store = app.get('store');
      const state$ = store.getState$();

      return streamProps()
        .set(state$, mapStateToProps)
        .setDispatch(mapDispatchToProps, store)
        .get$();
    })(Component);
  };
}

Further reading

maximuk commented 6 years ago

Also would be nice to have something like:

function someFunction(app) {
  return new Map([
    ['someVariable', app.get('service').getSomeVariable()],
    [app.get('region').getData$(), ({ regionProp }) => ({ regionProp })],
  ]);
}

export default connect(
  mapStateToProps, 
  dispatchableActions,
  someFunction
)(MyComponent);

Then iterate the Map in connect function

fahad19 commented 6 years ago

@maximuk: if you need app, isn't it better to use only existing observe HoC from frint-react? :)

fahad19 commented 6 years ago

if we go ahead with #391, this proposal can be considered redundant.

fahad19 commented 6 years ago

Closing this in favour of #391