https://github.com/gilbox/elegant-react
Functional React Architecture
https://github.com/gilbox/elegant-react
Last synced: 11 months ago
JSON representation
Functional React Architecture
- Host: GitHub
- URL: https://github.com/gilbox/elegant-react
- Owner: gilbox
- License: mit
- Created: 2015-06-14T16:19:59.000Z (about 11 years ago)
- Default Branch: master
- Last Pushed: 2016-04-17T17:41:42.000Z (over 10 years ago)
- Last Synced: 2025-09-07T06:35:19.561Z (11 months ago)
- Language: JavaScript
- Homepage:
- Size: 6.97 MB
- Stars: 62
- Watchers: 6
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# elegant-react
Functional React Architecture inspired by [omniscient](http://omniscientjs.github.io/) and [browser.html](https://github.com/mozilla/browser.html/).
Comments/suggestions/PRs are all welcome. This is still experimental.
BTW, you might also find it useful to use this in conjunction with [react-derive](https://github.com/gilbox/react-derive). And check out [elegant-react-hot-demo](https://github.com/gilbox/elegant-react-hot-demo) which combines them.
#### [Documentation](http://gilbox.github.io/elegant-react/docs/README.md.html)
## what is elegant-react?
`elegant-react` is an npm package. The source code for the npm package is in the `src/`
directory of this repo.
This github repo is also currently the home for a growing number of experiments
related to React functional patterns. The code for these experiments
live in the `examples/` dir. Some use the `elegant-react` npm package but others,
for the sake of simplicity, do not.
The `elegant-react` npm package provides:
- A simple ES7 class decorator ([`@elegant-react`](https://github.com/gilbox/elegant-react/blob/master/src/create-elegant-decorator.js))
that via a higher-order component (HoC) facilitates working with immutable data:
* Automatically optimizes your shouldComponentUpdate. In order
for this optimization to be efficient, all props passed to components should be
scalar or immutable values. If you need to further optimize `shouldComponentUpdate`
you can define your own, and because the `@elegant` decorator is a HoC there's
no need to worry about collisions.
* Allows designated props to be treated as *static* so that changes to those
props don't trigger render updates.
- A simple [subedit](https://github.com/gilbox/elegant-react/blob/master/src/index.js#L4) function that looks like this (if you're not using immutable-js, there are [alternatives to this `subedit` function](https://github.com/gilbox/elegant-react#dependencies)):
```javascript
const subedit = (edit, ...path) => transform =>
edit(state => state.updateIn(path, transform));
```
## about
This repo started off as a demonstration of some concepts that I wrote about in [this Medium article](https://medium.com/@gilbox/an-elegant-functional-architecture-for-react-faa3fb42b75b) and [this one](https://medium.com/p/7acf5d0cf00e) as well. However, since that time elegant-react
has continued to evolve and things have changed significantly. For the purpose of education,
you can check out the [elegant-react-og](https://github.com/gilbox/elegant-react) repo which
is a copy of the elegant-react repo immediately before it began to diverge from the content
in those two Medium articles.
## Installation
Install via npm
```bash
npm install elegant-react
```
## Bringing it into your project
Import it:
```javascript
import {elegant, subedit} from 'elegant-react';
```
Or if you'd like to enable debug mode:
```javascript
import ElegantReact from 'elegant-react';
const {elegant, subedit} = ElegantReact({debug: true});
```
Note: the `subedit` function is also available as `sub`. It's a personal
preference which you use. I like the way that `sub(edit, 'foo')` reads.
## react-native support
Require it:
```javascript
import {elegant, subedit} from 'elegant-react/native';
```
Or if you'd like to enable debug mode:
```javascript
import ElegantReact from 'elegant-react/native';
const {elegant, subedit} = ElegantReact({debug: true});
```
## Using in codepen, jsbin, etc.
Add the script:
//rawgit.com/gilbox/elegant-react/master/build/global/elegant-react.js
This exposes the global object `ElegantReact`.
```javascript
const {elegant, subedit} = ElegantReact;
```
Or if you'd like to enable `debug` mode:
```javascript
const {elegant, subedit} = ElegantReact({debug: true});
```
## Usage
First, make sure you understand the `subedit` (aka `sub`) function described in
[this Medium article](https://medium.com/@gilbox/an-elegant-functional-architecture-for-react-faa3fb42b75b)
Then add the `@elegant` decorator to your component, specifying which
props are static.
```javascript
const inc = n => n + 1;
@elegant({statics: ['editValue']})
class Item extends Component {
render() {
const {item,editValue} = this.props;
const onClick = _ => editValue(inc);
return
{ item.get('name') } - { item.get('value') }
}
}
```
Now put that component to use:
```javascript
const reverse = data => data.reverse();
@elegant({statics: ['edit']})
class Items extends Component {
render() {
const {items,edit} = this.props;
const children = items.toArray().map(
(item, index) =>
);
return
edit(reverse)}>reverse
- { children }
}
}
```
The rest of the source for this demo is [here](https://github.com/gilbox/elegant-react/blob/master/examples/reorder-items/app.js)
and you can [see it in action](http://gilbox.github.io/elegant-react/examples/reorder-items/demo.html)
as well.
## dependencies
You might notice that elegant-react has no `dependencies` nor `peerDependencies`
listed in it's package.json file. This is so it can support both react and react-native
from the same npm package.
Although it's not a hard dependency, the provided `subedit` function is known
to work with `immutable-js`. If you wish to use a different immutable lib,
just create your own subedit function and it should work.
- `sub`edit for [mori](http://swannodette.github.io/mori/) *(untested)*
```javascript
const sub = (edit, ...path) => transform =>
edit(state => mori.updateIn(state, path, transform));
```
- `sub`edit for [updeep](https://github.com/aaronjensen/updeep).
(There is a demo in the `examples/reorder-items-updeep/` dir.)
```javascript
import u from 'updeep'
const sub = (edit, ...path) =>
transform => edit(u.updateIn(path, transform));
```
- `sub`edit for [icepick](https://github.com/aearly/icepick) *(untested)*
```javascript
import i from 'icepick'
const sub = (edit, ...path) => transform =>
edit(state => i.updateIn(state, path, transform))
```
## Run the examples
Clone this repo, then:
```bash
npm install
npm run examples
```
... and navigate to [http://localhost:8080/webpack-dev-server/](http://localhost:8080/webpack-dev-server/)
## differences from omniscient
- elegant-react uses higher-order components where omniscient uses mixins
- elegant-react components use a decorator to specify which props are static while
omniscient uses a single prop called `statics`.
- omniscient will perform deep comparisons on props of any type with `lodash.isequal`,
elegant-react only performs shallow comparison assuming that if you need deep comparison
you will use immutable objects or define your own `shouldComponentUpdate`
- elegant-react uses idiomatic react approach ([see this article](https://medium.com/p/7acf5d0cf00e) for more info)
- omniscient supports components as function without JSX
- omniscient supports cursors
- omniscient is battle-tested
- omniscient is unit-tested
- omniscient is ~18kb minified. elegant-react is ~4kb
## live examples
- [Phone Input](http://gilbox.github.io/elegant-react/examples/phone-input-field/demo.html)
A very simple example of how to use `elegant-react` and a functional approach to creating
an input component with custom formatting and masking rules.
- [Address Book with Stream-based Plugins](http://gilbox.github.io/elegant-react/examples/address-book-store-streams/demo.html)
Demonstrates how to use streams to create an undo/redo plugin.
Introduces the concepts of `previousEditStream`, `editStream`, and `wiredStream` that allows a plugin to gain read and/or write
access only to specific parts of the application state.
- [Scroll Spring Animation](http://gilbox.github.io/elegant-react/examples/scroll-spring-animation/demo.html)
Demonstrates how to use `react-springs` (or `react-animation`) and how to create a scroll
handling component using the same functional technique.
- [Reorder Items](http://gilbox.github.io/elegant-react/examples/reorder-items/demo.html)
A very simple demo showing how to use `elegant-react`.
- [Form Validation (wip)](http://gilbox.github.io/elegant-react/examples/form-validation/demo.html)
Demonstrates how to create a robust plugin to handle validating form fields with a
json scema using the `jjv` npm package. Also demonstrates how to compose
decorators by combining `@elegant` with `@validationDecorator`.
- [Sticky](http://gilbox.github.io/elegant-react/examples/sticky/demo.html)
Make a `div` stick when the user scrolls the item past the top of the viewport.
- **[elegant-react-hot-demo](https://github.com/gilbox/elegant-react-hot-demo)** - This github repo demonstrates stream-based plugins (with flyd), animation with react-motion, hot reload, and time-travel scrubbing.
## credit
This project was originally a simplified version of [omniscient](http://omniscientjs.github.io/)
which promotes the functional approach of [browser.html](https://github.com/mozilla/browser.html/).
However, it has since evolved to become a more unique thing of it's own (see *differences from omniscient* above)