Skip to content
Merged
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
126 changes: 1 addition & 125 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,128 +127,4 @@ fn.updateState('some/nested/node', 'here i am', { rerender: false });

## The Advanced Guide

### The fn api

The fn api is accessible via actions.

#### updateState & updateMulti

`fn.updateState(node, value, options)` - Updates the state at a given node with the value.
The application will refresh unless `options.rerender` is set to false.
`node` can either be in directory format
- eg. `a/nested/node` or an array of strings
- eg. `[ 'a', 'nested', 'node' ]`

`fn.updateMulti([ { node: node, value: value }, {...} ], options)` - The same as `updateState`, however allows multiple updates to state at once.

eg.

```javascript

fn.updateMulti([
{ node: 'a/nested/node', value: 'hello' },
{ node: 'another/node', value: 'hello again'}
], { rerender: false })

```

#### Route Changes with fn.goto()

`fn.goto(route)` - Changes the URL to the new route. This updates `state.route` with the new url broken into segments.

eg. `myapp.com/page1/part_a` will produce `state.route` of `[ '', 'page1', 'part_a']`.

`fn.goto()` always triggers a state change and therefore an app refresh.

#### Dynamically add new actions with fn.addActions()

TODO

### Action Chaining

Actions can be chained together by simply passing `actions` into a given action as a parameter.
`actions` can then simply be called in the same way as you would from a component.

### Async Actions

There is nothing special that needs to be done to perform async actions.
Since `state` is the same `state` throughout the app, if the `state` outside the action changes,
the `state` inside the action changes too. Everything just stays in sync.

> Make sure that you never reassign `state`. i.e. something like `state = newState`, as this
will destroy any references to `state` throughout the app.

**Async example**

```javascript

const actions = (fn) => {
...
// incNumber always increments the current state
incNumber(fn) => (state) => {
setInterval( () => {
return fn.updateState('counter', state.counter + 1)
}, 1000);
}
...
}

```

### Engines. Actions that produce ongoing value streams

Engines are Asynchronous Actions that are able to be turned on and off. While in an 'on' state, they produce a value-stream (Multiple updates to State) until the 'off' switch is triggered.

A simple example is a button that when pushed, triggers a number to increment every second until the button is pushed again.

The actions for such an engine might look like...

```typescript

startCountEngine: () => {
if ( !state.countEngine.active ) {
const countEngineId = setInterval(() => {
fn.updateState('countEngine/value', state.countEngine.value + 1 )
}, 1000);
fn.updateMulti([
{ node: 'countEngine/active', value: true },
{ node: 'countEngine/id', value: countEngineId }
])
}
return;
},
stopCountEngine: () => {
clearInterval(state.countEngine.id);
fn.updateMulti([
{ node: 'countEngine/active', value: false },
{ node: 'countEngine/id', value: undefined }
], { rerender: false })
return;
}
```

This is all well and good, however sometimes we want to trigger an engine start when a particular component is in view and stop the engine when it is not.

React-Fn provides a `beforeRender` function that can be included in the app function's config object. This function takes in both State and Actions, and is called whenever the app is about to rerender (refresh).

By using `beforeRender`, and checking `state.route`, actions such as `stopCountEngine` can be called when a `route` meets a particular condition.

eg. The below example will trigger the `stopCountEngine` action when the route is myapp.com/page3.

```typescript

const appContainer = document.getElementById('app');

app(state, firstComponent, actions, appContainer, {
beforeRender: (state, actions) => {
switch(state.route[1]) {
case 'page3':
actions.stopCountEngine();
break;
}
}
});

```

> Note: It's very important to set ` { rerender: false } ` on any state changes within `beforeRender`, otherwise the app will loop continuously as it tries to rerender, followed by rerender, etc.
https://github.com/attack-monkey/react-fn/tree/develop/docs/TOC.md
4 changes: 4 additions & 0 deletions docs/Action-Chaining.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Action Chaining

Actions can be chained together by simply passing `actions` into a given action as a parameter.
`actions` can then simply be called in the same way as you would from a component.
25 changes: 25 additions & 0 deletions docs/Async-Actions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Async Actions

There is nothing special that needs to be done to perform async actions.
Since `state` is the same `state` throughout the app, if the `state` outside the action changes,
the `state` inside the action changes too. Everything just stays in sync.

> Make sure that you never reassign `state`. i.e. something like `state = newState`, as this
will destroy any references to `state` throughout the app.

## Async example**

```javascript

const actions = (fn) => {
...
// incNumber always increments the current state
incNumber(fn) => (state) => {
setInterval( () => {
return fn.updateState('counter', state.counter + 1)
}, 1000);
}
...
}

```
57 changes: 57 additions & 0 deletions docs/Engines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Engines. Actions that produce ongoing value streams

Engines are Asynchronous Actions that are able to be turned on and off. While in an 'on' state, they produce a value-stream (Multiple updates to State) until the 'off' switch is triggered.

A simple example is a button that when pushed, triggers a number to increment every second until the button is pushed again.

The actions for such an engine might look like...

```typescript

startCountEngine: () => {
if ( !state.countEngine.active ) {
const countEngineId = setInterval(() => {
fn.updateState('countEngine/value', state.countEngine.value + 1 )
}, 1000);
fn.updateMulti([
{ node: 'countEngine/active', value: true },
{ node: 'countEngine/id', value: countEngineId }
])
}
return;
},
stopCountEngine: () => {
clearInterval(state.countEngine.id);
fn.updateMulti([
{ node: 'countEngine/active', value: false },
{ node: 'countEngine/id', value: undefined }
], { rerender: false })
return;
}
```

This is all well and good, however sometimes we want to trigger an engine start when a particular component is in view and stop the engine when it is not.

React-Fn provides a `beforeRender` function that can be included in the app function's config object. This function takes in both State and Actions, and is called whenever the app is about to rerender (refresh).

By using `beforeRender`, and checking `state.route`, actions such as `stopCountEngine` can be called when a `route` meets a particular condition.

eg. The below example will trigger the `stopCountEngine` action when the route is myapp.com/page3.

```typescript

const appContainer = document.getElementById('app');

app(state, firstComponent, actions, appContainer, {
beforeRender: (state, actions) => {
switch(state.route[1]) {
case 'page3':
actions.stopCountEngine();
break;
}
}
});

```

> Note: It's very important to set ` { rerender: false } ` on any state changes within `beforeRender`, otherwise the app will loop continuously as it tries to rerender, followed by rerender, etc.
36 changes: 36 additions & 0 deletions docs/Fn-Api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# The fn api

The fn api is accessible via actions.

## updateState & updateMulti

`fn.updateState(node, value, options)` - Updates the state at a given node with the value.
The application will refresh unless `options.rerender` is set to false.
`node` can either be in directory format
- eg. `a/nested/node` or an array of strings
- eg. `[ 'a', 'nested', 'node' ]`

`fn.updateMulti([ { node: node, value: value }, {...} ], options)` - The same as `updateState`, however allows multiple updates to state at once.

eg.

```javascript

fn.updateMulti([
{ node: 'a/nested/node', value: 'hello' },
{ node: 'another/node', value: 'hello again'}
], { rerender: false })

```

## Route Changes with fn.goto()

`fn.goto(route)` - Changes the URL to the new route. This updates `state.route` with the new url broken into segments.

eg. `myapp.com/page1/part_a` will produce `state.route` of `[ '', 'page1', 'part_a']`.

`fn.goto()` always triggers a state change and therefore an app refresh.

## Dynamically add new actions with fn.addActions()

TODO
10 changes: 10 additions & 0 deletions docs/TOC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# React-Fn Docs

## Migration
- [Migrating from v1 to v2](https://github.com/attack-monkey/react-fn/tree/develop/docs/Migration.md)

## Actions
- [Fn API](https://github.com/attack-monkey/react-fn/tree/develop/docs/Fn-Api.md)
- [Chaining Actions](https://github.com/attack-monkey/react-fn/tree/develop/docs/Action-Chaining.md)
- [Async Actions](https://github.com/attack-monkey/react-fn/tree/develop/docs/Async-Actions.md)
- [Engines: Actions that produce ongoing value streams](https://github.com/attack-monkey/react-fn/tree/develop/docs/Engines.md)