isomorfeus-react 16.6.6 → 16.6.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4e054aded3a383c11557dd6b808a758f74d7f4d58946a8408f1f1e47b16671d
4
- data.tar.gz: de1fa3a6a6ee48d6b8358b7e47be4d2134a582602614d2a71a20a919c41e15b0
3
+ metadata.gz: 7734c66d2190367c11ef62d2a95658b144eea4fc35d9840e23d0b684297857bf
4
+ data.tar.gz: c7adfe966a2e6b1b5921981d72266673877dd559fd7d95ab4a49870aece9552f
5
5
  SHA512:
6
- metadata.gz: a700840562899b706241697d6bbb810652fd025bdfb7b7959e13f59212d69be859763452a242e32f730b679d3dc7e9c0f9c79a07d985d9fdc55b6874a0c97931
7
- data.tar.gz: '08af3b1cee362c6d9cd64a64db009976dde8c976dc4a1a2072870e7af321639813217b262f08c1195dc621d28ebcdc5f412cab49f791c3fca7e35586ce83b34f'
6
+ metadata.gz: 97c9f1935d81da9b7debd7fce453d32e5b1810230d40ffcd0f9af98050e69e3c48a5fdc864e60c3c2e9098de1ee6c647aa3957ed9f0c35af8bfc736ddae40dd7
7
+ data.tar.gz: ab9c75bf388786ef5e4d5ac046bb5b4a8bf94aba2fd99f12426529b8ff0e14b6dcd44936c4f2b8750ba032b884906a7070fb0fd996fe50c49d257b83c46612be
data/README.md ADDED
@@ -0,0 +1,439 @@
1
+ # isomorfeus-react
2
+
3
+ Develop React components for Opal Ruby along with very easy to use and advanced React-Redux Components.
4
+
5
+ ### Community and Support
6
+ At the [Isomorfeus Framework Project](http://isomorfeus.com)
7
+
8
+ ## Versioning
9
+ isomorfeus-react version follows the React version which features and API it implements.
10
+ Isomorfeus-react 16.5.x implements features and the API of React 16.6 and should be used with React 16.6
11
+
12
+ ## Installation
13
+ To install React with the matching version:
14
+ ```
15
+ yarn add react@16.6
16
+ ```
17
+ then add to the Gemfile:
18
+ ```ruby
19
+ gem 'isomorfeus-react' # this will also include isomorfeus-redux
20
+ ```
21
+ then `bundle install`
22
+ and to your client code add:
23
+ ```ruby
24
+ require 'isomorfeus-react' # this will also require isomorfeus-redux
25
+ ```
26
+
27
+ ### Dependencies
28
+
29
+ For full functionality the following are required:
30
+ Ruby Gems:
31
+ - [Opal with ES6 modules](https://github.com/opal/opal/pull/1976)
32
+ - [Opal Webpack Loader](https://github.com/isomorfeus/opal-webpack-loader)
33
+ - [Opal Autoloader](https://github.com/janbiedermann/opal-autoloader)
34
+ - [Isomorfeus-Speednode](https://github.com/isomorfeus/isomorfeus-speednode)
35
+ - [Isomorfeus-Redux](https://github.com/isomorfeus/isomorfeus-redux)
36
+
37
+ For the Gemfile:
38
+ ```ruby
39
+ gem 'opal', github: 'janbiedermann/opal', branch: 'es6_modules_1_1'
40
+ gem 'opal-webpack-loader', '~> 0.8.4'
41
+ gem 'opal-autoloader', '~> 0.0.3'
42
+ gem 'isomorfeus-redux', '~> 4.0.4'
43
+ gem 'isomorfeus-speednode', '~> 0.2.3'
44
+ ```
45
+ Javascript Npms:
46
+ - opal-webpack-laoder
47
+ - react
48
+ - react-router
49
+ - redux
50
+
51
+ for package.json:
52
+ ```json
53
+ "opal-webpack-loader": "^0.8.4",
54
+ "react": "16.8",
55
+ "react-dom": "16.8",
56
+ "react-router": "5.0.0",
57
+ "react-router-dom": "5.0.0",
58
+ "redux": "^4.0.1"
59
+ ```
60
+ ## Usage
61
+ Because isomorfeus-react follows closely the React principles/implementation/API and Documentation, most things of the official React documentation
62
+ apply, but in the Ruby way, see:
63
+ - https://reactjs.org/docs/getting-started.html
64
+
65
+ React, Redux and accompanying libraries must be imported and made available in the global namespace in the application javascript entry file,
66
+ with webpack this can be ensured by assigning them to the global namespace:
67
+ ```javascript
68
+ import * as Redux from 'redux';
69
+ import React from 'react';
70
+ import ReactDOM from 'react-dom';
71
+ global.Redux = Redux;
72
+ global.React = React;
73
+ global.ReactDOM = ReactDOM;
74
+
75
+ // for routing support
76
+ import { BrowserRouter, Link, NavLink, Route, Switch } from 'react-router-dom';
77
+ global.BrowserRouter = BrowserRouter;
78
+ global.Link = Link;
79
+ global.NavLink = NavLink;
80
+ global.Route = Route;
81
+ global.Switch = Switch;
82
+ ```
83
+
84
+ Following features are presented with its differences to the Javascript React implementation, along with enhancements and the advanced components.
85
+
86
+ ### Component Types
87
+ - [Class Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/class_component.md)
88
+ - [Pure Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/pure_component.md)
89
+ - [Function Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/function_component.md)
90
+ - [Redux Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/redux_component.md)
91
+ - [Lucid App, Lucid Router and Lucid Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/lucid_component.md)
92
+ - [React Javascript Component](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/javascript_component.md)
93
+
94
+ Which component to use?
95
+ - Usually LucidApp, LucidRouter and LucidComponent along with some javascript components.
96
+ - For improved performance small Function Components may help at critical spots.
97
+
98
+ ### Props
99
+ [Props](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/props.md)
100
+
101
+ ### State
102
+ [State](https://github.com/isomorfeus/isomorfeus-react/blob/master/ruby/docs/state.md)
103
+
104
+ ### Lifecycle Callbacks
105
+ All lifecycle callbacks that are available in the matching React version are available as DSL. Callback names are underscored.
106
+ Callback names prefixed with UNSAFE_ in React are prefixed with unsafe_ in ruby.
107
+ Example:
108
+ ```ruby
109
+ class MyComponent < React::Component::Base
110
+ render do
111
+ SPAN { 'some more text' }
112
+ end
113
+
114
+ component_did_mount do
115
+ `console.log("MyComponent mounted!")`
116
+ end
117
+ end
118
+ ```
119
+
120
+ ### Events
121
+ Event names are underscored in ruby: `onClick` becomes `on_click`. The conversion for React is done automatically.
122
+
123
+ Event handlers must be declared using the `event_handler` DSL. This is to make sure, that they are not recreated during render and can be properly
124
+ compared by reference by shouldComponentUpdate(). Use the DSL like so:
125
+ ```ruby
126
+ class MyComponent < React::Component::Base
127
+ event_handler :handle_click do |event|
128
+ state.toggler = !state.toggler
129
+ end
130
+
131
+ render do
132
+ SPAN(on_click: :handle_click) { 'some more text' }
133
+ SPAN(on_click: :handle_click) { 'a lot more text' } # event handlers can be reused
134
+ end
135
+ end
136
+ ```
137
+
138
+ To the event handler the event is passed as argument. The event is a ruby object `React::SyntheticEvent` and supports all the methods, properties
139
+ and events as the React.Synthetic event. Methods are underscored. Example:
140
+ ```ruby
141
+ class MyComponent < React::Component::Base
142
+ event_handler :handle_click do |event|
143
+ event.prevent_default
144
+ event.current_target
145
+ end
146
+
147
+ render do
148
+ SPAN(on_click: :handle_click) { 'some more text' }
149
+ end
150
+ end
151
+ ```
152
+ Targets of the event, like current_target, are wrapped Elements as supplied by opal-browser.
153
+
154
+ #### Events and Function Components
155
+ The event_handler DSL can be used within the React::FunctionComponent::Creator. However, function component dont react by themselves to events,
156
+ the event handler must be applied to a element.
157
+ ```ruby
158
+ class React::FunctionComponent::Creator
159
+ event_handler :show_red_alert do |event|
160
+ `alert("RED ALERT!")`
161
+ end
162
+
163
+ event_handler :show_orange_alert do |event|
164
+ `alert("ORANGE ALERT!")`
165
+ end
166
+
167
+ function_component 'AFunComponent' do
168
+ SPAN(on_click: props.on_click) { 'Click for orange alert! ' } # event handler passed in props, applied to a element
169
+ SPAN(on_click: :show_red_alert) { 'Click for red alert! ' } # event handler directly applied to a element
170
+ end
171
+
172
+ function_component 'AnotherFunComponent' do
173
+ AFunComponent(on_click: :show_orange_alert, text: 'Fun') # event handler passed as prop, but must be applied to element, see above
174
+ end
175
+ end
176
+ ```
177
+ ### Render blocks
178
+ render or element or component blocks work like ruby blocks, the result of the last expression in a block is returned and then rendered,
179
+ but only if it is a string or a React Element.
180
+ HTML Elements and Components at any place in the blocks are rendered too.
181
+ Examples:
182
+ ```ruby
183
+ class MyComponent < React::Component::Base
184
+ render do
185
+ SPAN { "string" } # this string is rendered in a SPAN HTML Element
186
+ SPAN { "another string" } # this string is rendered in a SPAN too
187
+ end
188
+ end
189
+ ```
190
+ ```ruby
191
+ class MyComponent < React::Component::Base
192
+ render do
193
+ "string" # this string is NOT rendered, its not returned from the block and its not wrapped in a Element,
194
+ # to render it, wrap it in a element or fragment
195
+ "another string" # this string is returned from the block, so its rendered
196
+ end
197
+ end
198
+ ```
199
+ ```ruby
200
+ class MyComponent < React::Component::Base
201
+ render do
202
+ Fragment { "string" } # this string is rendered without surrounding element
203
+ 100 # this is not a string, so its NOT rendered, to render it, simply convert it to a string: "#{100}" or 100.to_s
204
+ end
205
+ end
206
+ ```
207
+ There is a shorthand "string param syntax". Its advantages are:
208
+ - reduced asset size, because it reduces the amount of compiled blocks, strings are passed as param instead
209
+ - improved performance, because it reduces the amount of executed blocks, strings are passed as param instead
210
+
211
+ Its disadvantages are:
212
+ - it looks a bit odd when other params are passed
213
+
214
+ The first render block example in "string param syntax":
215
+ ```ruby
216
+ class MyComponent < React::Component::Base
217
+ render do
218
+ SPAN "string" # this string is rendered in a SPAN HTML Element, short and handy
219
+ SPAN "another string" # this string is rendered in a SPAN too, short and handy
220
+
221
+ # "string param syntax" with additional params:
222
+ SPAN({class: 'design'}, "yet another string") # <- not recommended
223
+ # for comparison the "string block syntax" with additonal params
224
+ SPAN(class: 'design') { 'even a string' } # <- recommended, looks better
225
+ end
226
+ end
227
+ ```
228
+ ### Rendering HTML or SVG Elements
229
+ Elements are rendered using a DSL which provides all Elements supported by React following these specs:
230
+ - https://www.w3.org/TR/html52/fullindex.html#index-elements
231
+ - https://www.w3.org/TR/SVG11/eltindex.html
232
+
233
+ The DSL can be used like so:
234
+ ```ruby
235
+ class MyComponent < React::Component::Base
236
+ render do
237
+ SPAN { 'some more text' } # upper case
238
+ span { 'so much text' } # lower case
239
+ end
240
+ end
241
+ ```
242
+ Use whichever you prefer. There are some clashes with opal ruby kernel methods, like `p 'text'`, that may have to be considered.
243
+
244
+ ### Accessibility
245
+ Props like `aria-label` must be written underscored `aria_label`. They are automatically converted for React. Example:
246
+ ```ruby
247
+ class MyComponent < React::Component::Base
248
+ render do
249
+ SPAN(aria_label: 'label text') { 'some more text' }
250
+ end
251
+ end
252
+ ```
253
+
254
+ ### Fragments
255
+ Fragments can be created like so:
256
+ ```ruby
257
+ class MyComponent < React::Component::Base
258
+ render do
259
+ Fragment do
260
+ SPAN { 'useful text' }
261
+ SPAN { 'extremely useful text' }
262
+ end
263
+ end
264
+ end
265
+ ```
266
+
267
+ ### Portals
268
+ Portals can be created like so:
269
+ ```ruby
270
+ class MyComponent < React::Component::Base
271
+ render do
272
+ Portal(`document.querySelector('div')`) do
273
+ SPAN { 'useful text' }
274
+ end
275
+ end
276
+ end
277
+ ```
278
+ Portals currently require a native DOM node as argument. (This may change to something conveniently provided by opal-browser.)
279
+
280
+ ### StrictMode
281
+ React.StrictMode can be used like so:
282
+ ```ruby
283
+ class MyComponent < React::Component::Base
284
+ render do
285
+ StrictMode do
286
+ SPAN { 'useful text' }
287
+ end
288
+ end
289
+ end
290
+ ```
291
+
292
+ ### Ref
293
+ Refs must be declared using the `ref` DSL. This is to make sure, that they are not recreated during render and can be properly
294
+ compared by reference by shouldComponentUpdate(). Use the DSL like so:
295
+ ```ruby
296
+ class MyComponent < React::Component::Base
297
+ ref :my_ref # a simple ref
298
+ ref :my_other_ref do |ref| # a ref with block
299
+ ref.current
300
+ end
301
+
302
+ render do
303
+ SPAN(ref: :my_ref) { 'useful text' } # refs can then be passed as prop
304
+ end
305
+ end
306
+ ```
307
+ If the ref declaration supplies a block, the block receives a `React::Ref` ruby instance as argument. `ref.current`may then be the ruby component or
308
+ native DOM node. ()The latter may change to something conveniently provided by opal-browser.)
309
+
310
+ ### Context
311
+ A context can be created using `React.create_context(constant_name, default_value)`. Constant_name must be a string like `"MyContext"`.
312
+ The context withs its Provider and Consumer can then be used like a component:
313
+ ```ruby
314
+ React.create_context("MyContext", 'div')
315
+
316
+ class MyComponent < React::Component::Base
317
+ render do
318
+ MyContext.Provider(value="span") do
319
+ MyOtherComponent()
320
+ end
321
+ end
322
+ end
323
+ ```
324
+ or the consumer:
325
+ ```ruby
326
+ class MyOtherComponent < React::Component::Base
327
+ render do
328
+ MyContext.Consumer do |value|
329
+ Sem.Button(as: value) { 'useful text' }
330
+ end
331
+ end
332
+ end
333
+ ```
334
+
335
+ ### Using React Router
336
+ First the Components of React Router must be imported and made available in the global context:
337
+ ```javascript
338
+ import * as ReactRouter from 'react-router';
339
+ import * as ReactRouterDOM from 'react-router-dom';
340
+ import { BrowserRouter, Link, NavLink, Route, Switch } from 'react-router-dom';
341
+
342
+ global.ReactRouter = ReactRouter;
343
+ global.ReactRouterDOM = ReactRouterDOM;
344
+ global.BrowserRouter = BrowserRouter;
345
+ global.Link = Link;
346
+ global.NavLink = NavLink;
347
+ global.Route = Route;
348
+ global.Switch = Switch;
349
+ ```
350
+ Only import whats needed, or import HashRouter instead of BrowserRouter.
351
+ Then the Router components can be used as an other component:
352
+ ```ruby
353
+ class RouterComponent < React::Component::Base
354
+ render do
355
+ DIV do
356
+ BrowserRouter do
357
+ Switch do
358
+ Route(path: '/my_path/:id', exact: true, component: MyOtherComponent.JS[:react_component])
359
+ Route(path: '/', strict: true, component: MyCompnent.JS[:react_component])
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end
365
+ ```
366
+ The Javascript React components of the ruby class must be passed as shown above. The child components then get the Router props
367
+ (match, history, location) passed in their props. They can be accessed like this:
368
+ ```ruby
369
+ class MyOtherComponent < React::Component::Base
370
+
371
+ render do
372
+ Sem.Container(text_align: 'left', text: true) do
373
+ DIV do
374
+ SPAN { 'match :id is: ' }
375
+ SPAN { props.match.id }
376
+ end
377
+ DIV do
378
+ SPAN { 'location pathname is: ' }
379
+ SPAN { props.location.pathname }
380
+ end
381
+ DIV do
382
+ SPAN { 'number of history entries: ' }
383
+ SPAN { props.history.length }
384
+ end
385
+ end
386
+ end
387
+ end
388
+ ```
389
+ Otherwise the React Router documentation applies: https://reacttraining.com/react-router/
390
+
391
+ ### Code Splitting with Suspense (doc is wip)
392
+
393
+ React.lazy is availalable and so is the Suspense Component, in a render block:
394
+ ```ruby
395
+ render do
396
+ Suspense do
397
+ MyComponent()
398
+ end
399
+ end
400
+ ```
401
+ ### Development Tools
402
+ The React Developer Tools allow for analyzing, debugging and profiling components. A very helpful toolset and working very nice with isomorfeus-react:
403
+ https://github.com/facebook/react-devtools
404
+
405
+ ### Execution Environment
406
+ Code can run in 3 different environments:
407
+ - On the Browser, for normal execution
408
+ - On nodejs, for server side rendering
409
+ - On the server, for normal execution of server side code
410
+
411
+ The following helpers are available to determine the execution environment:
412
+ - `Isomorfeus.on_browser?` - true if running on the browser, otherwise false
413
+ - `Isomorfeus.on_ssr?` - true if running on node for server side rendering, otherwise false
414
+ - `Isomorfeus.on_server?` - true if running on the server, otherwise false
415
+
416
+ ### Server Side Rendering
417
+ SSR is turned on by default in production and turned of in development. SSR is done in node using isomorfeus-speednode.
418
+ Components that depend on a browser can be shielded from rendering in node by using the above execution environment helper methods.
419
+ Example:
420
+ ```ruby
421
+ class MyOtherComponent < React::Component::Base
422
+
423
+ render do
424
+ if Isomorfeus.on_browser?
425
+ SomeComponentDependingOnWindow()
426
+ else
427
+ DIV()
428
+ end
429
+ end
430
+ end
431
+ ```
432
+
433
+ ### Hot Module Reloading
434
+
435
+ HMR is supported when using LucidApp as top level component.
436
+ A render after a code update can be triggered using:
437
+ ```ruby
438
+ Isomorfeus.force_render
439
+ ```