HenrikJoreteg / redux-bundler

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

React binding #1

Closed marvinroger closed 6 years ago

marvinroger commented 6 years ago

Hi!

First, thanks for sharing this awesome project. I can definitely see this redux-bundler getting the traction it deserves.

It's written in the README that there's no React binding yet. I am pretty sure it would help for the adoption of this project, and, considering, as you say...

writing those bindings would not be hard, mostly just copying what I did for preact for react

... I think it's a pity not to have it. 😉

I'd have helped if I could, but I am not familiar enough with the inner of React.

developit commented 6 years ago

Since Henrik mentioned the preact bindings are similar to Unistore's, I thought I'd drop a few links here pointing to where Unistore handles its React bindings.

Bindings: https://github.com/developit/unistore/blob/master/src/integrations/react.js

Microbundle build for both bindings: (produces cjs/es/umd for each in a directory) https://github.com/developit/unistore/blob/e8e468c687e0a30faf02995764300879df31251b/package.json#L13

Jest tests for the React bindings: (I might port these to karmatic) https://github.com/developit/unistore/tree/master/test/react


edit: I just noticed @HenrikJoreteg was smart and split the integrations out into different packages, so react bindings are much easier here. Good thinking!

marvinroger commented 6 years ago

Here you go:

import {createElement, Component, Children} from 'react'

const CONTEXT_TYPES = {
  store: () => {}
}

export class Provider extends Component {
  getChildContext () {
    return { store: this.props.store }
  }

  render () {
    return Children.only(this.props.children)
  }
}
Provider.childContextTypes = CONTEXT_TYPES

export const connect = (...args) => {
  const Comp = args.slice(-1)[0]
  const strings = args.length > 1 ? args.slice(0, -1) : []
  const actionCreators = []
  const keysToWatch = []
  strings.forEach((str) => {
    if (str.slice(0, 6) === 'select') {
      keysToWatch.push(str)
      return
    }
    if (str.slice(0, 2) === 'do') {
      actionCreators.push(str)
      return
    }
    throw Error(`CanNotConnect ${str}`)
  })

  class Connect extends Component {
    constructor (props, context) {
      super(props, context)
      const store = context.store
      this.state = store.select(keysToWatch)
      this.unsubscribe = store.subscribeToSelectors(keysToWatch, this.setState.bind(this))
      this.actionCreators = {}
      actionCreators.forEach((name) => {
        this.actionCreators[name] = (...args) => store[name](...args)
      })
    }

    componentWillUnmount () {
      this.unsubscribe()
    }

    render () {
      return createElement(Comp, Object.assign({}, this.props, this.state, this.actionCreators))
    }
  }
  Connect.contextTypes = CONTEXT_TYPES

  return Connect
}
marvinroger commented 6 years ago

Thanks for the tips @developit I won't publish the package myself as I quite did nothing here

HenrikJoreteg commented 6 years ago

@marvinroger @developit thanks! Here ya go: https://github.com/HenrikJoreteg/redux-bundler-react