Skip to content

Commit

Permalink
GitBook: [pre-release] 18 pages modified
Browse files Browse the repository at this point in the history
  • Loading branch information
leastbad authored and gitbook-bot committed Aug 8, 2021
1 parent a37e3cf commit 99997df
Showing 1 changed file with 54 additions and 38 deletions.
92 changes: 54 additions & 38 deletions docs/rtfm/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,36 +76,42 @@ end

It is possible that you might want to abort a Reflex and prevent it from executing. For example, the user might not have appropriate permissions to complete an action, or perhaps some other side effect like missing data would cause an exception if the Reflex was allowed to continue.

To do so, place `throw: abort` in a `before_reflex` callback on your Reflex class. An aborted Reflex will trigger the `halted` life-cycle stage on the client.
An aborted Reflex will trigger the `halted` life-cycle stage instead of the `after` and `finalize` stages on the client. You can learn more about how aborted Reflexes behave in different scenarios in [Understanding Stages](lifecycle.md#understanding-stages).

{% hint style="warning" %}
Halted Reflexes do not execute `after` or `finalize` callbacks.
To abort a Reflex, call `throw :abort` inside of a `before_reflex` callback on your Reflex class.

{% hint style="info" %}
Please note that all statements run before a Reflex is aborted have already happened; there is no "roll-back" of database updates, CableReady broadcasts or other changes. Even setting a Reflex Morph type or Reflex Payload will survive an abort, so long as they happen before `throw :abort` occurs.
{% endhint %}

## Client-Side Reflex Callbacks
## Client-Side Reflex Life-Cycle

StimulusReflex gives you the ability to inject custom JavaScript at five distinct moments **around** sending an event to the server and updating the DOM. These hooks allow you to improve the user experience and handle edge cases.
StimulusReflex gives you the ability to inject custom JavaScript at six distinct moments **around** the life-cycle of a Reflex. Developers can use a combination of **callback methods**, **event handlers** and **Promise resolution** to improve the user experience and handle edge cases.

1. **`before`** prior to sending a request over the web socket
2. **`success`** after the server side Reflex succeeds and the DOM has been updated
3. **`error`** whenever the server side Reflex raises an error
4. **`halted`** Reflex canceled by developer with `throw :abort` in the `before_reflex` callback
5. **`after`** follows either `success` or `error` immediately before DOM manipulations
1. **`before`** prior to sending a Reflex over the WebSocket
2. **`success`** after the server-side Reflex processes successfully
3. **`error`** after the server-side Reflex raises an error
4. **`halted`** Reflex canceled by developer with `throw :abort` in a `before_reflex` callback
5. **`after`** follows _either_ `success` or `error` immediately before DOM manipulations
6. **`finalize`** occurs immediately after all DOM manipulations are complete

{% hint style="info" %}
**Using life-cycle callback methods is not a requirement.**
#### Order of operations

Think of them as power tools that can help you build more sophisticated results. 👷
{% endhint %}
The order of operations for life-cycle management techniques is:

If you define a method with a name that matches what the library searches for, it will run at just the right moment. **If there's no method defined, nothing happens.** StimulusReflex will only look for these methods in Stimulus controllers that extend `ApplicationController` or have called `StimulusReflex.register(this)` in their `connect()` function.
1. Promise resolution
2. Callback methods
3. Event handlers

There are two kinds of callback methods: **generic** and **custom**. Generic callback methods are invoked for every Reflex action on a controller. Custom callback methods are only invoked for specific Reflex actions.
There is no "best" way to handle life-cycle stages, and most developers use a blend of the available tools depending on the situation and their preferred development style. While the APIs are different, we've worked hard to make sure that each mechanism has access to all of the Reflex data available at each stage of the process.

{% hint style="info" %}
**Using life-cycle stages is not a requirement.**

StimulusReflex also emits life-cycle events which can be captured in other Stimulus controllers, [jQuery plugins](https://github.com/leastbad/jquery-events-to-dom-events) or even the console.
Think of them as power tools that can help you build more sophisticated results. 👷
{% endhint %}

### Understanding Stages
#### Understanding Stages

Most of the time, it's reasonable to expect that your Reflexes will follow a predictable cycle: `before` -> `success` -> `after` -> `finalize`.

Expand All @@ -119,9 +125,19 @@ Nothing Morphs have no CableReady operations to wait for, so there is nothing to

Nothing Morphs support `success` methods but do not emit `success` events.

### Generic Life-cycle Methods
### Callback Methods

StimulusReflex controllers automatically support five generic life-cycle callback methods. These methods fire for every Reflex action handled by the controller.
If you define a method with a name that matches what the library searches for, it will run at just the right moment. **If there's no method defined, nothing happens.** StimulusReflex will only look for these methods in Stimulus controllers that extend `ApplicationController` or have called `StimulusReflex.register(this)` in their `connect()` function.

{% hint style="warning" %}
Unlike ActiveSupport callbacks, if you define the same callback in a parent class \(like `ApplicationController`\) and a class that extends it, only the one in the extended class will execute.
{% endhint %}

There are two kinds of callback methods: **generic** and **custom**. Generic callback methods are invoked for every Reflex action on a controller. Custom callback methods are only invoked for specific Reflex actions.

#### Generic Life-cycle Methods

StimulusReflex controllers automatically support six generic life-cycle callback methods. These methods fire for every Reflex action handled by the controller.

1. `beforeReflex`
2. `reflexSuccess`
Expand All @@ -131,7 +147,7 @@ StimulusReflex controllers automatically support five generic life-cycle callbac
6. `finalizeReflex`

{% hint style="warning" %}
While this is perfect for basic Reflexes with a small number of actions, most developers quickly switch to using [Custom Life-cycle Methods](lifecycle.md#custom-life-cycle-methods), which allow you to define different callbacks for every action.
While this is perfect for basic Reflexes with a small number of actions, most developers quickly switch to using [Custom Life-cycle Methods](lifecycle.md#custom-life-cycle-methods), which allow you to define different callbacks for every Reflex action.
{% endhint %}

In this example, we update each anchor's text before invoking the server side Reflex:
Expand Down Expand Up @@ -159,7 +175,7 @@ export default class extends ApplicationController {
```
{% endcode %}

### Custom Life-cycle Methods
#### Custom Life-cycle Methods

StimulusReflex controllers can define up to six custom life-cycle callback methods for **each** Reflex action. These methods use a naming convention **based on the name of the Reflex**. The naming follows the pattern `<actionName>Success` and matches the camelCased name of the action.

Expand Down Expand Up @@ -197,17 +213,15 @@ export default class extends ApplicationController {
```
{% endcode %}

Adapting the Generic example, we've refactored our controller to capture the `before` callback events for each anchor individually.
Adapting the Generic example, we've refactored our controller to execute the `before` callback methods for each anchor individually.

{% hint style="info" %}
**It's not required to implement all life-cycle methods.** Pick and choose which life-cycle callback methods make sense for your application. The answer is frequently **none**.
{% endhint %}

### Conventions

#### Method Names

Life-cycle callback methods apply a naming convention based on your Reflex actions. For example, the Reflex `ExampleReflex#do_stuff` will produce the following camel-cased life-cycle callback methods.
Life-cycle callback methods apply a naming convention based on your Reflex actions. For example, the Reflex `ExampleReflex#do_stuff` will search for the following camel-cased life-cycle callback methods:

1. `beforeDoStuff`
2. `doStuffSuccess`
Expand Down Expand Up @@ -235,7 +249,7 @@ Both generic and custom life-cycle callback methods share the same arguments:

**reflexId** - a UUID4 or developer-provided unique identifier for each Reflex

### Life-cycle Events
### Event Handlers

If you need to know when a Reflex method is called, but you're working outside of the Stimulus controller that initiated it, you can subscribe to receive DOM events.

Expand Down Expand Up @@ -283,34 +297,30 @@ In addition to DOM events, StimulusReflex will also emits duplicate [jQuery even

These jQuery events have the same name and `details` accessors as the DOM events.

### Promises
### Promise Resolution

Are you a hardcore JavaScript developer? A props power-lifter? Then you'll be pleased to know that in addition to life-cycle methods and events, StimulusReflex allows you to write promise resolver functions:

```javascript
this.stimulate('Comments#create')
.then(() => this.doSomething())
.catch(() => this.handleError())
.then(this.handleSuccess)
.catch(this.handleError)
```

You can get a sense of the possibilities:

```javascript
this.stimulate('Post#publish')
.then(promise => {
const { data, element, event, payload } = promise
const { attrs, reflexId } = data
const { data, element, event, payload, reflexId } = promise
// * data - the data sent from the client to the server over the web socket to invoke the reflex
// * element - the element that triggered the reflex
// * event - the source event
// * payload - optional return data passed from the Reflex method
// * attrs - an object that represents the attributes of the element that triggered the reflex
// * reflexId - a unique identifier for this specific reflex invocation
})
.catch(promise => {
const { data, element, event, payload } = promise
const { attrs, reflexId } = data
const { error } = event.detail.stimulusReflex
const { data, element, event, payload, reflexId, error } = promise
// * error - the error message from the server
})
```
Expand All @@ -320,7 +330,7 @@ You can get the `reflexId` of an unresolved promise:
```javascript
const snail = this.stimulate('Snail#secrete')
console.log(snail.reflexId)
snail.then(trail => {})
snail.then(trail => console.log)
```

#### Configuring Promise resolution timing
Expand All @@ -347,10 +357,16 @@ Take care to design your application such that you're always targeting elements
In addition to the Reflex life-cycle mechanisms, the StimulusReflex client library emits its own set of handy DOM events which you can hook into and use in your applications.
* `stimulus-reflex:action-cable:connected`
* `stimulus-reflex:action-cable:disconnected`
* `stimulus-reflex:action-cable:rejected`
* `stimulus-reflex:ready`
In previous versions, ActionCable was assumed; in future versions of the library, other transport mechanisms will be available. **Legacy library events are now deprecated** and **will be removed** in the future:
* `stimulus-reflex:connected`
* `stimulus-reflex:disconnected`
* `stimulus-reflex:rejected`
* `stimulus-reflex:ready`
All four events fire on `document`.
Expand Down

0 comments on commit 99997df

Please sign in to comment.