diff --git a/README.md b/README.md index 7dc353e..bfcda70 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/Action-Chaining.md b/docs/Action-Chaining.md new file mode 100644 index 0000000..faed980 --- /dev/null +++ b/docs/Action-Chaining.md @@ -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. \ No newline at end of file diff --git a/docs/Async-Actions.md b/docs/Async-Actions.md new file mode 100644 index 0000000..ebb7c59 --- /dev/null +++ b/docs/Async-Actions.md @@ -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); + } + ... +} + +``` diff --git a/docs/Engines.md b/docs/Engines.md new file mode 100644 index 0000000..9f7565d --- /dev/null +++ b/docs/Engines.md @@ -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. \ No newline at end of file diff --git a/docs/Fn-Api.md b/docs/Fn-Api.md new file mode 100644 index 0000000..96bd380 --- /dev/null +++ b/docs/Fn-Api.md @@ -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 \ No newline at end of file diff --git a/docs/TOC.md b/docs/TOC.md new file mode 100644 index 0000000..ff5ad10 --- /dev/null +++ b/docs/TOC.md @@ -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) \ No newline at end of file