You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Your Hyperstack Application is built from a series of *Components* which are Ruby Classes that display portions of the UI. Hyperstack Components are implemented using [React](https://reactjs.org/), and can interoperate with existing React components and libraries. Here is a simple example that displays a ticking clock:
6
2
7
3
```ruby
8
4
# Components inherit from the HyperComponent base class
9
5
# which supplies the DSL to translate from Ruby into React
10
6
# function calls
11
7
classClock < HyperComponent
12
-
# before_mount is an example of a life cycle method.
13
-
before_mount do
14
-
# before the component is first rendered (mounted)
8
+
# Components can be parameterized.
9
+
# in this case you can override the default
10
+
# with a different format
11
+
param format:"%m/%d/%Y %I:%M:%S"
12
+
# After_mount is an example of a life cycle method.
13
+
after_mount do
14
+
# Before the component is first rendered (mounted)
15
15
# we setup a periodic timer that will update the
16
16
# current_time instance variable every second.
17
+
# The mutate method signals a change in state
17
18
every(1.second) { mutate @current_time=Time.now }
18
19
end
19
20
# every component has a render block which describes what will be
@@ -22,21 +23,9 @@ class Clock < HyperComponent
22
23
# Components can render other components or primitive HTML or SVG
23
24
# tags. Components also use their state to determine what to render,
24
25
# in this case the @current_time instance variable
25
-
DIV { @current_time.strftime("%m/%d/%Y %I:%M:%S")
26
+
DIV { @current_time.strftime(format) }
26
27
end
27
28
end
28
29
```
29
30
30
-
This documentation will cover the following core concepts, many of which
31
-
are touched on in the above simple example:
32
-
33
-
+[HTML & CSS DSL](html-css.md) which provides Ruby implementations of all of the HTML and CSS elements
34
-
+[The Component DSL](components.md) is a Ruby DSL which wraps ReactJS Components
35
-
+[Lifecycle Methods](lifecycle-methods.md) are methods which are invoked before, during and after rendering
36
-
+[State](state.md) - components rerender as needed when state changes.
37
-
+[Event Handlers](event-handlers.md) allow any HTML element or Component to respond to an event, plus custom events can be described.
38
-
+[JavaScript Components](javascript-components.md) access to the full universe of JS libraries in your Ruby code
39
-
+[Client-side Routing](hyper-router.md) a Ruby DSL which wraps ReactRouter
40
-
+[Stores](hyper-store.md) for application level state and Component communication
41
-
+[Elements and Rendering](elements-and-rendering.md) details of the underlying mechanisms.
42
-
+[Further Reading](further-reading.md) on React and Opal
31
+
The following chapters cover these aspects and more in detail.
The following sections give a brief orientation to the structure of a component and the methods that are used to define and control its behavior.
13
4
14
5
## Defining a Component
15
6
@@ -24,7 +15,7 @@ end
24
15
25
16
## The `render` Callback
26
17
27
-
At a minimum every *concrete* component class must define a `render` block which generates one or more child elements. Those children may in turn have an arbitrarily deep structure. **[More on concrete and abstract components](notes.md#abstract-and-concrete-components)**
18
+
At a minimum every *concrete* component class must define a `render` block which generates one or more child elements. Those children may in turn have an arbitrarily deep structure. **[More on concrete and abstract components...](notes.md#abstract-and-concrete-components)**
28
19
29
20
```ruby
30
21
classComponent < HyperComponent
@@ -55,9 +46,7 @@ class FirstComponent < HyperComponent
55
46
end
56
47
```
57
48
58
-
Note that you should never redefine the `new` or `initialize` methods, or call them directly. The equivalent of `initialize` is the `before_mount` method.
59
-
60
-
> The one exception to using `new` is within a spec to create a "headless" component in order to access its internal state and methods.
49
+
> While a component is defined as a class, and a rendered component is an instance of that class, we do not in general use the `new` method, or need to modify the components `initialize` method.
61
50
62
51
### Invoking Components
63
52
@@ -68,15 +57,76 @@ MyCustomComponent {} # ok
68
57
MyCustomComponent# <--- breaks
69
58
>```
70
59
71
-
## Multiple Components
60
+
## Component Params
61
+
62
+
A component can receive params to customize its look and behavior:
63
+
64
+
```Ruby
65
+
classSayHello < HyperComponent
66
+
param :to
67
+
render(DIV, class: :hello) do
68
+
"Hello #{to}!"
69
+
end
70
+
end
71
+
72
+
...
73
+
74
+
SayHello(to:"Joe")
75
+
```
76
+
77
+
Components can receive new params, causing the component to update. **[More on Params ...](params.md)**.
78
+
79
+
## Component State
80
+
81
+
Component also have *state*, which is stored in instance variables. You signal a state change using the `mutate` method. Component state is a fundamental concept covered **[here](state.md)**.
82
+
83
+
84
+
## Life Cycle Callbacks
85
+
86
+
A component may be updated during its life time due to either changes in state or receiving new params. You can hook into the components life cycle using the
87
+
the life cycle methods. Two of the most common lifecycle methods are `before_mount` and `after_mount` that are called before a component first renders, and
88
+
just after a component first renders respectively.
89
+
90
+
```RUBY
91
+
classClock < HyperComponent
92
+
param format:"%m/%d/%Y %I:%M:%S"
93
+
after_mount do
94
+
every(1.second) { mutate @current_time=Time.now }
95
+
end
96
+
render do
97
+
DIV { @current_time.strftime(format) }
98
+
end
99
+
end
100
+
```
101
+
102
+
The complete list of life cycle methods and their syntax is discussed in detail in the **[Lifecycle Methods](/lifecycle-methods)** section.
103
+
104
+
## Events, Event Handlers, and Component Callbacks
105
+
106
+
Events such as mouse clicks trigger callbacks, which can be attached using the `on` method:
107
+
108
+
```ruby
109
+
classClickCounter < HyperComponent
110
+
before_mount { @clicks=0 }
111
+
defadverb
112
+
@clicks.zero? ?'please' : 'again'
113
+
end
114
+
render(DIV) do
115
+
BUTTON { "click me #{adverb}" }
116
+
.on(:click) { mutate @clicks+=1 } # attach a callback
117
+
DIV { "I've been clicked #{pluralize(@clicks, 'time')}" } if@clicks>0
118
+
end
119
+
end
120
+
```
72
121
73
-
So far, we've looked at how to write a single component to display data. Next let's examine how components are combined to build an application.
122
+
This example also shows how events and state mutations work together to change the look of the display. It also demonstrates that because a HyperComponent
123
+
is just a Ruby class you can define helper methods, use conditional logic, and call on predefined methods like `pluralize`.
74
124
75
-
By building modular components that reuse other components with well-defined interfaces you can _separate the different concerns_ of your app. By building a custom component library for your application, you are expressing your UI in a way that best fits your domain.
125
+
In addition components can fire custom events, and make callbacks to the upper level components. **[More details ...](events-and-callbacks.md)**
76
126
77
-
### Composition Example
127
+
##Application Structure
78
128
79
-
Let's create a simple Avatar component which shows a profile picture and username using the Facebook Graph API.
129
+
Your Application is built out of many smaller components using the above features to control the components behavior and communicate between components. To conclude this section let's create a simple Avatar component which shows a profile picture and username using the Facebook Graph API.
0 commit comments