8000 GitHub - gregberge/recompact at v2.2.3
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
This repository was archived by the owner on Nov 26, 2018. It is now read-only.

gregberge/recompact

Repository files navigation

Recompact

Build Status

Recompact is a set of React higher-order components for reactive programming. It's a tiny framework inspired by Recompose to unleash the power of observables inside your React application.

Installation and Usage

To install the stable version:

yarn add recompact

To import the entire core set of functionality:

import recompact from 'recompact';

To import only what you need (this is useful for size-sensitive bundling):

import mapProps from 'recompact/mapProps';

Recompact vs. Recompose

Recompact is a drop-in replacement* for Recompose with better performance.

* Except for the callback of withState's state updater.

Flattened React components tree

You may have noticed the "compact" keyword in "Recompact". It's the main differences between Recompose and Recompact. Recompact compacts all higher-order components into a single one. It results in a flatter React tree. A flatter React tree has several advantages: performance improvement, better debugging (especially in React Developer Tools) and easier testing.

Let's take two components using composition, one using recompose and one using recompact.

The two components are similar, but if you take a look at the React component tree (using React Developer Tool), you can see that the component using recompact is flat:

recompact-vs-recompose

New methods

Recompact also features higher-order components that are not included in Recompose:

And some very specific higher-order components that give you a lot of power:

Using connectObs and withObs to build your application

One of the biggest challenges in applications is communication between components. Imagine that you are building a complex app with a counter and a button to increment this counter, spread across completely different parts of the UI.

Recompact makes it is easy to deal with this kind of problem. Here is what we need to do:

  • Provide a counter observable at the point of sharing (all children that need to access it must be in the subtree of this component).
  • Connect the counter prop where we need to display it.
  • Connect the onIncrementCounter function where we need to interact with it.
// counterLogic.js
import connectObs from 'recompact/connectObs'
import withObs from 'recompact/withObs'
import { Subject } from 'modules/rxjs'

export const provideCounter = withObs(() => {
  const incrementCounter$ = new Subject()
  const counter$ = incrementCounter$.startWith(0).scan(counter => counter + 1)
  return { counter$, incrementCounter$ }
});

export const connectCounterValue = connectObs(({counter$}) => ({counter: counter$}))

export const connectCounterControls = connectObs(({incrementCounter$}) => ({
  onIncrementCounter: incrementCounter$,
}))

We have created three functions for each concern: providing the counter observables, connecting the counter value and connecting the counter controls.

Collisions of observables

Observables are stored under a symbolize key in the context (like you know, context is global in the application). When you provide observables into the context at the root point, a provide can override your key and you can have an unpredictable behaviour.

To avoid this problem, you have two solutions:

  • Naming observables with a specific name (counter$ VS globalApplicationCounter$)
  • Using ES6 Symbols as key

Symbols are immutable and unique object that can be used as an object key, if you use a symbol as an object key you are 100% sure that it could not be overridden. Warning: properties using Symbol as key are not enumerable by default, if you log the observables object you will not see them.

// counterLogic.js
import connectObs from 'recompact/connectObs'
import withObs from 'recompact/withObs'
import Rx from 'rxjs'

const COUNTER$ = Symbol('counter$')
const INCREMENT_COUNTER$ = Symbol('incrementCounter$')

export const provideCounter = withObs(() => {
  const incrementCounter$ = new Rx.Subject()
  const counter$ = incrementCounter$.startWith(0).scan(counter => counter + 1)
  return {
    [COUNTER$]: counter$,
    [INCREMENT_COUNTER$]: incrementCounter$,
  }
});

export const connectCounterValue = connectObs(({
  [COUNTER$]: counter$,
}) => ({
  counter: counter$,
}))

export const connectCounterControls = connectObs(({
  [INCREMENT_COUNTER$]: incrementCounter$,
}) => ({
  onIncrementCounter: incrementCounter$,
}))

We replaced keys by Symbols, we are now 100% safe and we don't use any exotic name.

Connecting all together

// App.js
import compose from 'recompact/compose'
import setDisplayName from 'recompact/setDisplayName'
import CounterIncrementButton from './CounterIncrementButton'
import CounterDisplay from './CounterDisplay'
import { provideCounter } from './counterLogic'

export default recompose.compose(
  setDisplayName('App'),
  provideCounter,
)(({onIncrementCounter}) => (
  <div>
    <CounterIncrementButton />
    <CounterDisplay />
  </div>
))

First we create an app and we provide counter in it.

// CounterIncrementButton.js
import setDisplayName from 'recompact/setDisplayName'
import MyButton from './MyButton'
import { connectCounterControls } from './counterLogic'

export default recompose.compose(
  setDisplayName('CounterIncrementButton'),
  connectCounterControls,
)(({onIncrementCounter}) => (
  <MyButton onClick={onIncrementCounter}>Increment</MyButton>
))

We create our CounterIncrementButton and we use connectCounterControls to connect it.

// CounterDisplay.js
import setDisplayName from 'recompact/setDisplayName'
import { connectCounterValue } from './hoc/counter'

export default recompose.compose(
  recompose.setDisplayName('CounterDisplay'),
  connectCounterValue,
)(({counter}) => <div>{counter}</div>)

We create our CounterDisplay and we use connectCounterValue to connect it.

License

MIT

About

⚛ A set of React higher-order components utilities. Drop-in replacement for recompose.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 9

Languages

0