Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Satchel v5 #182

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
node-version: '14.x'
- run: yarn --frozen-lockfile
- run: yarn build
- run: yarn test
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12.x'
node-version: '14.x'
registry-url: 'https://registry.npmjs.org'
- run: yarn
- run: yarn build
Expand Down
81 changes: 46 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
# Satchel

Satchel is a dataflow framework based on the [Flux architecture](http://facebook.github.io/react/blog/2014/05/06/flux.html). It is characterized by exposing an observable state that makes view updates painless and efficient.
Satchel is a dataflow framework based on the [Flux architecture](http://facebook.github.io/react/blog/2014/05/06/flux.html). It is characterized by exposing an observable state that makes view updates painless and efficient.

[![npm](https://img.shields.io/npm/v/satcheljs.svg)](https://www.npmjs.com/package/satcheljs)
[![Build Status](https://travis-ci.org/Microsoft/satcheljs.svg?branch=master)](https://travis-ci.org/Microsoft/satcheljs)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Influences

Satchel is an attempt to synthesize the best of several dataflow patterns typically used to drive a React-based UI. In particular:
Satchel is an attempt to synthesize the best of several dataflow patterns typically used to drive a React-based UI. In particular:

* [Flux](http://facebook.github.io/react/blog/2014/05/06/flux.html) is not a library itself, but is a dataflow pattern conceived for use with React. In Flux, dataflow is unidirectional, and the only way to modify state is by dispatching actions through a central dispatcher.
* [Redux](http://redux.js.org/index.html) is an implementation of Flux that consolidates stores into a single state tree and attempts to simplify state changes by making all mutations via pure functions called reducers. Ultimately, however, we found reducers and immutable state cumbersome to deal with, particularly in a large, interconnected app.
* [MobX](http://mobxjs.github.io/mobx/index.html) provides a seamless way to make state observable, and allows React to listen to state changes and rerender in a very performant way. Satchel uses MobX under the covers to allow React components to observe the data they depend on.
- [Flux](http://facebook.github.io/react/blog/2014/05/06/flux.html) is not a library itself, but is a dataflow pattern conceived for use with React. In Flux, dataflow is unidirectional, and the only way to modify state is by dispatching actions through a central dispatcher.
- [Redux](http://redux.js.org/index.html) is an implementation of Flux that consolidates stores into a single state tree and attempts to simplify state changes by making all mutations via pure functions called reducers. Ultimately, however, we found reducers and immutable state cumbersome to deal with, particularly in a large, interconnected app.
- [MobX](http://mobxjs.github.io/mobx/index.html) provides a seamless way to make state observable, and allows React to listen to state changes and rerender in a very performant way. Satchel uses MobX under the covers to allow React components to observe the data they depend on.

## Advantages

There are a number of advantages to using Satchel to maintain your application state:

* Satchel enables a very **performant UI**, only rerendering the minimal amount necessary. MobX makes UI updates very efficient by automatically detecting specifically what components need to rerender for a given state change.
* Satchel's datastore allows for **isomorphic JavaScript** by making it feasible to render on the server and then serialize and pass the application state down to the client.
* Satchel supports **middleware** that can act on each action that is dispatched. (For example, for tracing or performance instrumentation.)
* Satchel is **type-safe** out of the box, without any extra effort on the consumer's part.
- Satchel enables a very **performant UI**, only rerendering the minimal amount necessary. MobX makes UI updates very efficient by automatically detecting specifically what components need to rerender for a given state change.
- Satchel's datastore allows for **isomorphic JavaScript** by making it feasible to render on the server and then serialize and pass the application state down to the client.
- Satchel supports **middleware** that can act on each action that is dispatched. (For example, for tracing or performance instrumentation.)
- Satchel is **type-safe** out of the box, without any extra effort on the consumer's part.

## Installation

Expand All @@ -39,15 +39,20 @@ In order to use Satchel with React, you'll also need MobX and the MobX React bin

The following examples assume you're developing in Typescript.

### Create a satchel instance

```typescript
import { createSatchel } from 'satcheljs';

export const mySatchel = createSatchel(options);
```

### Create a store with some initial state

```typescript
import { createStore } from 'satcheljs';
import { mySatchel } from './mySatchel';

let getStore = createStore(
'todoStore',
{ todos: [] }
);
let getStore = mySatchel.createStore('todoStore', { todos: [] });
```

### Create a component that consumes your state
Expand All @@ -62,7 +67,9 @@ class TodoListComponent extends React.Component<any, any> {
render() {
return (
<div>
{getStore().todos.map(todo => <div>{todo.text}</div>)}
{getStore().todos.map(todo => (
<div>{todo.text}</div>
))}
</div>
);
}
Expand All @@ -71,17 +78,14 @@ class TodoListComponent extends React.Component<any, any> {

### Implement an action creator

Note that, as a convenience, Satchel action creators created with the `action` API both *create* and *dispatch* the action.
Note that, as a convenience, Satchel action creators created with the `action` API both _create_ and _dispatch_ the action.
This is typically how you want to use action creators.
If you want to create and dispatch the actions separately you can use the `actionCreator` and `dispatch` APIs.

```typescript
import { action } from 'satcheljs';
import { mySatchel } from './mySatchel';

let addTodo = action(
'ADD_TODO',
(text: string) => ({ text: text })
);
let addTodo = mySatchel.action('ADD_TODO', (text: string) => ({ text: text }));

// This creates and dispatches an ADD_TODO action
addTodo('Take out trash');
Expand All @@ -94,13 +98,18 @@ If you're using TypeScript, the type of `actionMessage` is automatically inferre

```typescript
import { mutator } from 'satcheljs';
import { mySatchel } from './mySatchel';

mutator(addTodo, (actionMessage) => {
const todoMutator = mutator(addTodo, (actionMessage) => {
getStore().todos.push({
id: Math.random(),
text: actionMessage.text
});
};

export function initializeMutators() {
mySatchel.register(todoMutator);
}
```

### Orchestrators
Expand All @@ -113,16 +122,18 @@ The following example shows how an orchestrator can persist a value to a server

```typescript
import { action, orchestrator } from 'satcheljs';
import { mySatchel } from './mySatchel';

let requestAddTodo = action(
'REQUEST_ADD_TODO',
(text: string) => ({ text: text })
);
let requestAddTodo = mySatchel.action('REQUEST_ADD_TODO', (text: string) => ({ text: text }));

orchestrator(requestAddTodo, async (actionMessage) => {
const requestAddTodoOrchestrator = orchestrator(requestAddTodo, async actionMessage => {
await addTodoOnServer(actionMessage.text);
addTodo(actionMessage.text);
});

export function initializeOrchestrators() {
mySatchel.register(requestAddTodoOrchestrator);
}
```

### mutatorAction
Expand All @@ -133,18 +144,18 @@ Satchel provides this utility API which encapsulates action creation, dispatch,
The `addTodo` mutator above could be implemented as follows:

```typescript
let addTodo = mutatorAction(
'ADD_TODO',
function addTodo(text: string) {
getStore().todos.push({
id: Math.random(),
text: actionMessage.text
});
import { mySatchel } from './mySatchel';

let addTodo = mutatorAction(mySatchel, 'ADD_TODO', function addTodo(text: string) {
getStore().todos.push({
id: Math.random(),
text: actionMessage.text,
});
});
```

This is a succinct and easy way to write mutators, but it comes with a restriction:
the action creator is not exposed, so no *other* mutators or orchestrators can subscribe to it.
the action creator is not exposed, so no _other_ mutators or orchestrators can subscribe to it.
If an action needs multiple handlers then it must use the full pattern with action creators and handlers implemented separately.

## License - MIT
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "satcheljs",
"version": "4.3.1",
"version": "5.0.0-beta.1",
"description": "Store implementation for functional reactive flux.",
"lint-staged": {
"*.{ts,tsx}": [
Expand Down Expand Up @@ -40,7 +40,7 @@
"mobx": "^4.4.0",
"mobx-react": "^5.2.0",
"npm-run-all": "^4.0.2",
"prettier": "^1.19.1",
"prettier": "^3.3.3",
"react": "15.4.2",
"react-addons-test-utils": "~15.4.0",
"react-dom": "15.4.2",
Expand Down
68 changes: 0 additions & 68 deletions src/actionCreator.ts

This file was deleted.

17 changes: 0 additions & 17 deletions src/applyMiddleware.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/createActionId.ts

This file was deleted.

Loading
Loading