isomorfeus-react 16.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -0
  3. data/README.md +620 -0
  4. data/isomorfeus-react.gemspec +23 -0
  5. data/lib/isomorfeus-react.rb +131 -0
  6. data/lib/isomorfeus/config.rb +84 -0
  7. data/lib/isomorfeus/top_level.rb +48 -0
  8. data/lib/isomorfeus/view_helpers.rb +38 -0
  9. data/lib/lucid_app/api.rb +22 -0
  10. data/lib/lucid_app/base.rb +7 -0
  11. data/lib/lucid_app/context.rb +7 -0
  12. data/lib/lucid_app/mixin.rb +17 -0
  13. data/lib/lucid_app/native_component_constructor.rb +70 -0
  14. data/lib/lucid_component/api.rb +97 -0
  15. data/lib/lucid_component/base.rb +7 -0
  16. data/lib/lucid_component/event_handler.rb +17 -0
  17. data/lib/lucid_component/initializer.rb +12 -0
  18. data/lib/lucid_component/mixin.rb +17 -0
  19. data/lib/lucid_component/native_component_constructor.rb +131 -0
  20. data/lib/react.rb +147 -0
  21. data/lib/react/active_support_support.rb +13 -0
  22. data/lib/react/component/api.rb +226 -0
  23. data/lib/react/component/base.rb +9 -0
  24. data/lib/react/component/elements.rb +78 -0
  25. data/lib/react/component/event_handler.rb +19 -0
  26. data/lib/react/component/features.rb +47 -0
  27. data/lib/react/component/history.rb +36 -0
  28. data/lib/react/component/initializer.rb +11 -0
  29. data/lib/react/component/location.rb +15 -0
  30. data/lib/react/component/match.rb +31 -0
  31. data/lib/react/component/mixin.rb +19 -0
  32. data/lib/react/component/native_component_constructor.rb +76 -0
  33. data/lib/react/component/native_component_validate_prop.rb +37 -0
  34. data/lib/react/component/props.rb +49 -0
  35. data/lib/react/component/resolution.rb +71 -0
  36. data/lib/react/component/should_component_update.rb +14 -0
  37. data/lib/react/component/state.rb +52 -0
  38. data/lib/react/component/unsafe_api.rb +33 -0
  39. data/lib/react/context_wrapper.rb +47 -0
  40. data/lib/react/function_component/creator.rb +47 -0
  41. data/lib/react/function_component/resolution.rb +61 -0
  42. data/lib/react/function_component/runner.rb +19 -0
  43. data/lib/react/native_constant_wrapper.rb +34 -0
  44. data/lib/react/pure_component/base.rb +9 -0
  45. data/lib/react/pure_component/mixin.rb +17 -0
  46. data/lib/react/redux_component/api.rb +132 -0
  47. data/lib/react/redux_component/app_store_defaults.rb +38 -0
  48. data/lib/react/redux_component/app_store_proxy.rb +46 -0
  49. data/lib/react/redux_component/base.rb +9 -0
  50. data/lib/react/redux_component/class_store_proxy.rb +50 -0
  51. data/lib/react/redux_component/component_class_store_defaults.rb +40 -0
  52. data/lib/react/redux_component/component_instance_store_defaults.rb +41 -0
  53. data/lib/react/redux_component/initializer.rb +14 -0
  54. data/lib/react/redux_component/instance_store_proxy.rb +50 -0
  55. data/lib/react/redux_component/mixin.rb +18 -0
  56. data/lib/react/redux_component/native_component_constructor.rb +119 -0
  57. data/lib/react/redux_component/reducers.rb +53 -0
  58. data/lib/react/ref.rb +19 -0
  59. data/lib/react/synthetic_event.rb +53 -0
  60. data/lib/react/version.rb +3 -0
  61. data/lib/react_dom.rb +31 -0
  62. data/lib/react_dom_server.rb +17 -0
  63. metadata +167 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: cba3a632d5700b2370b2dc673eabc01aebac34c508680f79b01154ce856e5051
4
+ data.tar.gz: 4025af5f4037e829aacf72c91316b0da9b312209e92e242a8d8a127d58f1d109
5
+ SHA512:
6
+ metadata.gz: 8b178809f4a89d23283c1b0ccfa85f8df7e720388bf5516f70aa5083e38a7e88777992cfe7c92a53de74f0aa0cb78147ead4e8af11a6d58851c266b09fe862a8
7
+ data.tar.gz: a3da4df7f53d9f86b423750e5166ea214a359290c268d8e800f8254be688843732ce26d29c585dbd8f86f0b7d5580e06bf6afa2b721760024f712b95ccf9c612
data/Gemfile ADDED
@@ -0,0 +1 @@
1
+ gemspec
@@ -0,0 +1,620 @@
1
+ # isomorfeus-react
2
+
3
+ Develop React components for Opal Ruby along with very easy to use and advanced React-Redux Components.
4
+
5
+ ## Versioning
6
+ isomorfeus-react version follows the React version which features and API it implements.
7
+ Isomorfeus-react 16.5.x implements features and the API of React 16.5 and should be used with React 16.5
8
+
9
+ ## Installation
10
+ To install React with the matching version:
11
+ ```
12
+ yarn add react@16.5
13
+ ```
14
+ then add to the Gemfile:
15
+ ```ruby
16
+ gem 'isomorfeus-react' # this will also include isomorfeus-redux
17
+ ```
18
+ then `bundle install`
19
+ and to your client code add:
20
+ ```ruby
21
+ require 'isomorfeus-react' # this will also require isomorfeus-redux
22
+ ```
23
+ ## Usage
24
+ Because isomorfeus-react follows closely the React principles/implementation/API and Documentation, most things of the official React documentation
25
+ apply, but in the Ruby way, see:
26
+ - https://reactjs.org/docs/getting-started.html
27
+
28
+ Redux is also required, for the more advanced components to function properly.
29
+
30
+ React, Redux and accompanying libraries must be imported and made available in the global namespace in the application javascript entry file,
31
+ with webpack this can be ensured by assigning them to the global namespace:
32
+ ```javascript
33
+ import * as Redux from 'redux';
34
+ import React from 'react';
35
+ import ReactDOM from 'react-dom';
36
+ global.Redux = Redux;
37
+ global.React = React;
38
+ global.ReactDOM = ReactDOM;
39
+ ```
40
+
41
+ Following features are presented with its differences to the Javascript React implementation, along with enhancements and the advanced components.
42
+
43
+ ### Class Components
44
+ Class Components can be created in two ways, either by inheritance or by including a module.
45
+ Inheritance:
46
+ ```ruby
47
+ class MyComponent < React::Component::Base
48
+
49
+ end
50
+ ```
51
+ including a module:
52
+ ```ruby
53
+ class MyComponent
54
+ include React::Component::Mixin
55
+
56
+ end
57
+ ```
58
+
59
+ Each Component must have at least a render block:
60
+ ```ruby
61
+ class MyComponent < React::Component::Base
62
+ render do
63
+ DIV { "some text" }
64
+ end
65
+ end
66
+ ```
67
+
68
+ Class Component allow for the definition of a custom should_component_update? block, but that is optional:
69
+ ```ruby
70
+ class MyComponent < React::Component::Base
71
+ should_component_update? do |next_props, next_state|
72
+ return true # to always update for example
73
+ end
74
+
75
+ render do
76
+ DIV { "some text" }
77
+ end
78
+ end
79
+ ```
80
+ A default should_component_update? implementation is supplied. The default should_component_update? implementation for Class Components is most
81
+ efficient if complex props or state are used.
82
+
83
+ **Data flow of a React::Component:**
84
+ ![React::Component Data Flow](https://raw.githubusercontent.com/isomorfeus/isomorfeus-react/master/images/data_flow_component.png)
85
+
86
+
87
+ ### Pure Components
88
+ Pure Components can be created in two ways, either by inheritance or by including a module.
89
+ Inheritance:
90
+ ```ruby
91
+ class MyComponent < React::PureComponent::Base
92
+
93
+ end
94
+ ```
95
+ including a module:
96
+ ```ruby
97
+ class MyComponent
98
+ include React::PureComponent::Mixin
99
+
100
+ end
101
+ ```
102
+
103
+ Each Component must have at least a render block:
104
+ ```ruby
105
+ class MyComponent < React::PureComponent::Base
106
+ render do
107
+ DIV { "some text" }
108
+ end
109
+ end
110
+ ```
111
+
112
+ A PureComponent does not allow for the definition of a custom should_component_update? block. Its using the default React implementation instead.
113
+ Its recommended to use them only if no props or state are used or if props and state have simple values only, like strings or numbers.
114
+
115
+ **Data flow of a React::PureComponent:**
116
+ ![React::PureComponent Data Flow](https://raw.githubusercontent.com/isomorfeus/isomorfeus-react/master/images/data_flow_component.png)
117
+
118
+ ### Function Components
119
+ Function Components are created using a Ruby DSL that is used within the creator class:
120
+ ```ruby
121
+ class React::FunctionComponent::Creator
122
+ function_component 'MyComponent' do |props|
123
+ SPAN { props.text }
124
+ end
125
+ # Javascript .-notation can be used for the component name:
126
+ function_component 'MyObject.MyComponent' do |props|
127
+ SPAN { props.text }
128
+ end
129
+ end
130
+ ```
131
+ This creates a native javascript components.
132
+ The file containing the creator must be explicitly required, because the automatic resolution of Javascript constant names
133
+ is not done by opal-autoloader.
134
+
135
+ A Function Component can then be used in other Components:
136
+ ```ruby
137
+ class MyComponent < React::PureComponent::Base
138
+ render do
139
+ MyComponent(text: 'some text')
140
+ MyObject.MyComponent(text: 'more text')
141
+ end
142
+ end
143
+ ```
144
+ To get the native component, for example to pass it in props, javascript inlining can be used:
145
+ ```ruby
146
+ Route(path: '/fun_fun/:count', exact: true, component: `MyObject.MyComponent`)
147
+ ```
148
+
149
+ **Data flow of a React::FunctionComponent:**
150
+ ![React::FunctionComponent Data Flow](https://raw.githubusercontent.com/isomorfeus/isomorfeus-react/master/images/data_flow_function_component.png)
151
+
152
+ ### Props
153
+ In ruby props are underscored: `className -> class_name`. The conversion for React is done automatically.
154
+ Within a component props can be accessed using `props`:
155
+ ```ruby
156
+ class MyComponent < React::PureComponent::Base
157
+ render do
158
+ DIV { props.text }
159
+ end
160
+ end
161
+ ```
162
+ Props are passed as argument to the component:
163
+ ```ruby
164
+ class MyOtherComponent < React::PureComponent::Base
165
+ render do
166
+ MyComponent(text: 'some other text')
167
+ end
168
+ end
169
+ ```
170
+ Props can be declared and type checked and a default value can be given:
171
+ ```ruby
172
+ class MyComponent < React::PureComponent::Base
173
+ prop :text, class: String # a required prop of class String, class must match exactly
174
+ prop :other, is_a: Enumerable # a required prop, which can be a Array for example, but at least must be a Enumerable
175
+ prop :cool, default: 'yet some more text' # a optional prop with a default value
176
+ prop :even_cooler, class: String, required: false # a optional prop, which when given, must be of class String
177
+
178
+ render do
179
+ DIV { props.text }
180
+ end
181
+ end
182
+ ```
183
+
184
+ ### State
185
+ State can be accessed in components using `state`:
186
+ ```ruby
187
+ class MyComponent < React::PureComponent::Base
188
+ render do
189
+ if state.toggled
190
+ DIV { 'toggled' }
191
+ else
192
+ DIV { 'not toggled' }
193
+ end
194
+ end
195
+ end
196
+ ```
197
+ State can be intialized like so:
198
+ ```ruby
199
+ class MyComponent < React::PureComponent::Base
200
+ state.toggled = false
201
+
202
+ render do
203
+ if state.toggled
204
+ DIV { 'toggled' }
205
+ else
206
+ DIV { 'not toggled' }
207
+ end
208
+ end
209
+ end
210
+ ```
211
+ State can be changed like so, the component setState() will be called:
212
+ ```ruby
213
+ class MyComponent < React::PureComponent::Base
214
+ render do
215
+ if some_condition_is_met
216
+
217
+ state.toggled = true # calls components setState to cause a render
218
+
219
+ # or if a callback is needed:
220
+
221
+ set_state({toggled: true}) do
222
+ # some callback code here
223
+ end
224
+ end
225
+ if state.toggled
226
+ DIV { 'toggled' }
227
+ else
228
+ DIV { 'not toggled' }
229
+ end
230
+ end
231
+ end
232
+ ```
233
+ When changing state, the state is not immediately available, just like in React! For example:
234
+ ```ruby
235
+ class MyComponent < React::PureComponent::Base
236
+ render do
237
+ previous_state_value = state.variable
238
+ state.variable = next_state_value # even though this looks like a assignment, it causes a side effect
239
+ # state may be updated after the next render cycle
240
+ next_state_value == state.variable # very probably false here until next render
241
+ previous_state_value == state.variable # probably true here until next render
242
+
243
+ # to work with next_state_value, wait for the next render cycle, or just keep using the next_state_value variable here instead of state.value
244
+ end
245
+ end
246
+ ```
247
+ To make the side effect of a set_state more visible, state can be set by using a method call instead of a assignment:
248
+ ```ruby
249
+ class MyComponent < React::PureComponent::Base
250
+ render do
251
+ previous_state_value = state.variable
252
+ state.variable(next_state_value) # setting state with a method call, it causes a side effect
253
+ # state may be updated after the next render cycle
254
+ next_state_value == state.variable # very probably false here until next render
255
+ previous_state_value == state.variable # probably true here until next render
256
+
257
+ # to work with next_state_value, wait for the next render cycle, or just keep using the next_state_value variable here instead of state.value
258
+ end
259
+ end
260
+ ```
261
+ ### Lifecycle Callbacks
262
+ All lifecycle callbacks that are available in the matching React version are available as DSL. Callback names are underscored.
263
+ Callback names prefixed with UNSAFE_ in React are prefixed with unsafe_ in ruby.
264
+ Example:
265
+ ```ruby
266
+ class MyComponent < React::Component::Base
267
+ render do
268
+ SPAN { 'some more text' }
269
+ end
270
+
271
+ component_did_mount do
272
+ `console.log("MyComponent mounted!")`
273
+ end
274
+ end
275
+ ```
276
+
277
+ ### Events
278
+ Event names are underscored in ruby: `onClick` becomes `on_click`. The conversion for React is done automatically.
279
+
280
+
281
+ 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
282
+ compared by reference by shouldComponentUpdate(). Use the DSL like so:
283
+ ```ruby
284
+ class MyComponent < React::Component::Base
285
+ event_handler :handle_click do |event|
286
+ state.toggler = !state.toggler
287
+ end
288
+
289
+ render do
290
+ SPAN(on_click: :handle_click) { 'some more text' }
291
+ SPAN(on_click: :handle_click) { 'a lot more text' } # event handlers can be reused
292
+ end
293
+ end
294
+ ```
295
+
296
+ To the event handler the event is passed as argument. The event is a ruby object `React::SyntheticEvent` and supports all the methods, properties
297
+ and events as the React.Synthetic event. Methods are underscored. Example:
298
+ ```ruby
299
+ class MyComponent < React::Component::Base
300
+ event_handler :handle_click do |event|
301
+ event.prevent_default
302
+ event.current_target
303
+ end
304
+
305
+ render do
306
+ SPAN(on_click: :handle_click) { 'some more text' }
307
+ end
308
+ end
309
+ ```
310
+ Targets of the event, like current_target, are wrapped Elements as supplied by opal-browser.
311
+
312
+ #### Events and Function Components
313
+ The event_handler DSL can be used within the React::FunctionComponent::Creator. However, function component dont react by themselves to events,
314
+ the event handler must be applied to a element.
315
+ ```ruby
316
+ class React::FunctionComponent::Creator
317
+ event_handler :show_red_alert do |event|
318
+ `alert("RED ALERT!")`
319
+ end
320
+
321
+ event_handler :show_orange_alert do |event|
322
+ `alert("ORANGE ALERT!")`
323
+ end
324
+
325
+ function_component 'AFunComponent' do
326
+ SPAN(on_click: props.on_click) { 'Click for orange alert! ' } # event handler passed in props, applied to a element
327
+ SPAN(on_click: :show_red_alert) { 'Click for red alert! ' } # event handler directly applied to a element
328
+ end
329
+
330
+ function_component 'AnotherFunComponent' do
331
+ AFunComponent(on_click: :show_orange_alert, text: 'Fun') # event handler passed as prop, but must be applied to element, see above
332
+ end
333
+ end
334
+ ```
335
+ ### Render blocks
336
+ render or element or component blocks work like ruby blocks, the result of the last expression in a block is returned and then rendered,
337
+ but only if it is a string or a React Element.
338
+ HTML Elements and Components at any place in the blocks are rendered too.
339
+ Examples:
340
+ ```ruby
341
+ class MyComponent < React::Component::Base
342
+ render do
343
+ SPAN { "string" } # this string is rendered in a SPAN HTML Element
344
+ SPAN { "another string" } # this string is rendered in a SPAN too
345
+ end
346
+ end
347
+ ```
348
+ ```ruby
349
+ class MyComponent < React::Component::Base
350
+ render do
351
+ "string" # this string is NOT rendered, its not returned from the block and its not wrapped in a Element,
352
+ # to render it, wrap it in a element or fragment
353
+ "another string" # this string is returned from the block, so its rendered
354
+ end
355
+ end
356
+ ```
357
+ ```ruby
358
+ class MyComponent < React::Component::Base
359
+ render do
360
+ Fragment { "string" } # this string is rendered without surrounding element
361
+ 100 # this is not a string, so its NOT rendered, to render it, simply convert it to a string: "#{100}" or 100.to_s
362
+ end
363
+ end
364
+ ```
365
+ ### Rendering HTML or SVG Elements
366
+ Elements are rendered using a DSL which provides all Elements supported by React following these specs:
367
+ - https://www.w3.org/TR/html52/fullindex.html#index-elements
368
+ - https://www.w3.org/TR/SVG11/eltindex.html
369
+
370
+ The DSL can be used like so:
371
+ ```ruby
372
+ class MyComponent < React::Component::Base
373
+ render do
374
+ SPAN { 'some more text' } # upper case
375
+ span { 'so much text' } # lower case
376
+ end
377
+ end
378
+ ```
379
+ Use whichever you prefer. There are some clashes with opal ruby kernel methods, like `p 'text'`, that may have to be considered.
380
+
381
+ ### Accessibility
382
+ Props like `aria-label` must be written underscored `aria_label`. They are automatically converted for React. Example:
383
+ ```ruby
384
+ class MyComponent < React::Component::Base
385
+ render do
386
+ SPAN(aria_label: 'label text') { 'some more text' }
387
+ end
388
+ end
389
+ ```
390
+
391
+ ### Fragments
392
+ Fragments can be created like so:
393
+ ```ruby
394
+ class MyComponent < React::Component::Base
395
+ render do
396
+ Fragment do
397
+ SPAN { 'useful text' }
398
+ SPAN { 'extremely useful text' }
399
+ end
400
+ end
401
+ end
402
+ ```
403
+
404
+ ### Portals
405
+ Portals can be created like so:
406
+ ```ruby
407
+ class MyComponent < React::Component::Base
408
+ render do
409
+ Portal(`document.querySelector('div')`) do
410
+ SPAN { 'useful text' }
411
+ end
412
+ end
413
+ end
414
+ ```
415
+ Portals currently require a native DOM node as argument. (This may change to something conveniently provided by opal-browser.)
416
+
417
+ ### StrictMode
418
+ React.StrictMode can be used like so:
419
+ ```ruby
420
+ class MyComponent < React::Component::Base
421
+ render do
422
+ StrictMode do
423
+ SPAN { 'useful text' }
424
+ end
425
+ end
426
+ end
427
+ ```
428
+
429
+ ### Ref
430
+ Refs must be declared using the `ref` DSL. This is to make sure, that they are not recreated during render and can be properly
431
+ compared by reference by shouldComponentUpdate(). Use the DSL like so:
432
+ ```ruby
433
+ class MyComponent < React::Component::Base
434
+ ref :my_ref # a simple ref
435
+ ref :my_other_ref do |ref| # a ref with block
436
+ ref.current
437
+ end
438
+
439
+ render do
440
+ SPAN(ref: :my_ref) { 'useful text' } # refs can then be passed as prop
441
+ end
442
+ end
443
+ ```
444
+ 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
445
+ native DOM node. ()The latter may change to something conveniently provided by opal-browser.)
446
+
447
+ ### React Javascript Components
448
+ Native React Javascript Components must be available in the global namespace. When importing them with webpack,
449
+ this can be ensured by assigning them to the global namespace:
450
+ ```javascript
451
+ import * as Sem from 'semantic-ui-react'
452
+ global.Sem = Sem;
453
+ ```
454
+ They can then be used like so:
455
+ ```ruby
456
+ class MyComponent < React::Component::Base
457
+ render do
458
+ Sem.Button(as: 'a') { 'useful text' }
459
+ end
460
+ end
461
+ ```
462
+
463
+ Some Javascript components accept another Javascript component as property, like for example React Router. The Ruby class won't work here,
464
+ instead the Javascript React component of the Ruby class must be passed.
465
+ It can be accessed by using Opals JS syntax to get the React Component of the Ruby class:
466
+ ```ruby
467
+ Route(path: '/', strict: true, component: MyComponent.JS[:react_component])
468
+ ```
469
+ Native Javascript components can be passed using the Javascript inlining of Opal, this also works for function components:
470
+ ```ruby
471
+ Route(path: '/a_button', strict: true, component: `Sem.Button`)
472
+ ```
473
+
474
+ ### Context
475
+ A context can be created using `React.create_context(constant_name, default_value)`. Constant_name must be a string like `"MyContext"`.
476
+ The context withs its Provider and Consumer can then be used like a component:
477
+ ```ruby
478
+ React.create_context("MyContext", 'div')
479
+
480
+ class MyComponent < React::Component::Base
481
+ render do
482
+ MyContext.Provider(value="span") do
483
+ MyOtherComponent()
484
+ end
485
+ end
486
+ end
487
+ ```
488
+ or the consumer:
489
+ ```ruby
490
+ class MyOtherComponent < React::Component::Base
491
+ render do
492
+ MyContext.Consumer do |value|
493
+ Sem.Button(as: value) { 'useful text' }
494
+ end
495
+ end
496
+ end
497
+ ```
498
+
499
+ ### Using React Router
500
+ First the Components of React Router must be imported and made available in the global context:
501
+ ```javascript
502
+ import * as ReactRouter from 'react-router';
503
+ import * as ReactRouterDOM from 'react-router-dom';
504
+ import { BrowserRouter, Link, NavLink, Route, Switch } from 'react-router-dom';
505
+
506
+ global.ReactRouter = ReactRouter;
507
+ global.ReactRouterDOM = ReactRouterDOM;
508
+ global.BrowserRouter = BrowserRouter;
509
+ global.Link = Link;
510
+ global.NavLink = NavLink;
511
+ global.Route = Route;
512
+ global.Switch = Switch;
513
+ ```
514
+ Only import whats needed, or import HashRouter instead of BrowserRouter.
515
+ Then the Router components can be used as an other component:
516
+ ```ruby
517
+ class RouterComponent < React::Component::Base
518
+ render do
519
+ DIV do
520
+ BrowserRouter do
521
+ Switch do
522
+ Route(path: '/my_path/:id', exact: true, component: MyOtherComponent.JS[:react_component])
523
+ Route(path: '/', strict: true, component: MyCompnent.JS[:react_component])
524
+ end
525
+ end
526
+ end
527
+ end
528
+ end
529
+ ```
530
+ The Javascript React components of the ruby class must be passed as shown above. The child components then get the Router props
531
+ (match, history, location) passed in their props. They can be accessed like this:
532
+ ```ruby
533
+ class MyOtherComponent < React::Component::Base
534
+
535
+ render do
536
+ Sem.Container(text_align: 'left', text: true) do
537
+ DIV do
538
+ SPAN { 'match :id is: ' }
539
+ SPAN { props.match.id }
540
+ end
541
+ DIV do
542
+ SPAN { 'location pathname is: ' }
543
+ SPAN { props.location.pathname }
544
+ end
545
+ DIV do
546
+ SPAN { 'number of history entries: ' }
547
+ SPAN { props.history.length }
548
+ end
549
+ end
550
+ end
551
+ end
552
+ ```
553
+ Otherwise the React Router documentation applies: https://reacttraining.com/react-router/
554
+
555
+ ### React::ReduxComponent
556
+ This component is like a React::Component and in addition to it, allows do manage its state conveniently over redux using a simple DSL:
557
+ - `store` - works similar like the components state, but manages the components state with redux
558
+ - `class_store` - allows to have a class state, when changing this state, all instances of the component class change the state and render
559
+ - `app_store` - allows to access application state, when changing this state, all instances that have requested the same variables, will render.
560
+ ```ruby
561
+ class MyComponent < React::PureComponent::Base
562
+ store.a_var = 100 # set a initial value for the instance
563
+ class_store.another_var = 200 # set a initial value for the class
564
+ render do
565
+ # in a React::ReduxComponent state can be used for local state managed by react:
566
+ state.some_var
567
+ # in addition to that, store can be used for local state managed by redux:
568
+ store.a_var
569
+ # and for managing class state:
570
+ class_store.another_var
571
+ # and for managing application wide state:
572
+ app_store.yet_another_var
573
+ end
574
+ end
575
+ ```
576
+ Provided some middleware is used for redux, state changes using `store` or `class_store` can be watched, debugged and otherwise handled by redux
577
+ middleware.
578
+
579
+ The lifecycle callbacks starting with `unsafe_` are not supported.
580
+ Overwriting should_component_update is also not supported.
581
+
582
+ **Data flow of a React::ReduxComponent:**
583
+ ![React::ReduxComponent Data Flow](https://raw.githubusercontent.com/isomorfeus/isomorfeus-react/master/images/data_flow_redux_component.png)
584
+
585
+ ### LucidApp and LucidComponent
586
+ A LucidComponent works very similar like a React::ReduxComponent, the same `store` and `class_store` is available. The difference is, that the
587
+ data changes are passed using props instead of setting component state. Therefore, a LucidComponent needs a LucidApp as outer component.
588
+ LucidApp sets up a React::Context Provider, LucidComponent works as a React::Context Consumer.
589
+ ```ruby
590
+ class MyApp < LucidApp::Base # is a React::Context provider
591
+ render do
592
+ MyComponent()
593
+ end
594
+ end
595
+
596
+ class MyComponent < LucidComponent::Base # is a React::Context Consumer
597
+ store.a_var = 100 # set a initial value for the instance
598
+ class_store.another_var = 200 # set a initial value for the class
599
+ render do
600
+ # in a LucidComponent state can be used for local state managed by react:
601
+ state.some_var
602
+ # in addition to that, store can be used for local state managed by redux:
603
+ store.a_var
604
+ # and for managing class state:
605
+ class_store.another_var
606
+ # and for managing application wide state:
607
+ app_store.yet_another_var
608
+ end
609
+ end
610
+ ```
611
+
612
+ The lifecycle callbacks starting with `unsafe_` are not supported.
613
+ Overwriting should_component_update is also not supported.
614
+
615
+ **Data flow of a LucidComponent within a LucidApp:**
616
+ ![LucidComponent within a LucidApp Data Flow](https://raw.githubusercontent.com/isomorfeus/isomorfeus-react/master/images/data_flow_lucid_component.png)
617
+
618
+ ### Development Tools
619
+ The React Developer Tools allow for analyzing, debugging and profiling components. A very helpful toolset and working very nice with isomorfeus-react:
620
+ https://github.com/facebook/react-devtools