Add doc about controlled inputs & workarounds

This commit is contained in:
Juho Teperi 2019-04-26 13:47:11 +03:00
parent d809a5a202
commit 2d0ec89ad7
3 changed files with 52 additions and 1 deletions

30
doc/ControlledInputs.md Normal file
View File

@ -0,0 +1,30 @@
# Controlled inputs
Reagent uses async rendering which cause problems with controlled inputs. If
the input element is created directly by Reagent (i.e. `[:input ...]` in hiccup), [a
workaround](https://github.com/reagent-project/reagent/blob/master/src/reagent/impl/template.cljs#L132-L238)
can be applied, but if the input is created by JS library (i.e. JSX `<input>`
or React `create-element`), Reagent doesn't see
the element so the workaround can't be applied.
Due to async rendering, the DOM update doesn't occur during the event handler,
but some time later. In certain cases, like when the cursor is not at the end
of the input, updating the DOM input value causes the cursor to move to the
end of the input. Without async rendering, browsers probably implement logic
to keep the cursor position if the value is updated during event handler.
Reagent workaround works by changing the React input element into
uncontrolled input (i.e. the DOM value is not updated by React). Instead
Reagent will update DOM itself if the Reagent input value property changes.
This enables Reagent to check the cursor position before updating the
value, and if needed, save and restore the cursor position
after updating the value.
For JS libraries, usually the best solution is if the library provides an option to
use custom component to create the input element, which enables
Reagent to create the input element:
## Examples
- [Material UI](./examples/material-ui.md)
- [Smooth UI](./examples/smooth-ui.md)

View File

@ -8,7 +8,8 @@
["[WIP] Managing State: atoms, cursors, Reactions, and tracking" {:file "doc/ManagingState.md"}]
["Batching and Timing: How Reagent Renders Changes to Application State" {:file "doc/BatchingAndTiming.md"}]
["Interop with React" {:file "doc/InteropWithReact.md"}]
["React Features" {:file "doc/ReactFeatures.md"}]]
["React Features" {:file "doc/ReactFeatures.md"}]
["Controlled Inputs" {:file "doc/ControlledInputs.md"}]]
["Frequently Asked Questions" {}
["Why isn't my Component re-rendering?" {:file "doc/FAQ/ComponentNotRerendering.md"}]
["How do I use React's \"refs\"" {:file "doc/FAQ/UsingRefs.md"}]

20
doc/examples/smooth-ui.md Normal file
View File

@ -0,0 +1,20 @@
# Smooth UI
Smooth UI has the same problem with [controlled inputs](../CotrolledInputs.md)
as [Material UI](./material-ui.md).
The problem can be solved by providing custom component to Smooth UI inputs
which will create the Input element using Reagent, enabling Reagent to use
it's workaround logic to control input value and cursor position:
```cljs
(def r-input (r/reactify-component
(fn [props]
;; Omit:
; https://github.com/smooth-code/smooth-ui/blob/c5f3c75a438a04e766dbedeafc2be54252a5338e/packages/shared/core/createComponent.js#L31
; https://github.com/smooth-code/ smooth-ui/blob/c5f3c75a438a04e766dbedeafc2be54252a5338e/packages/shared/core/Input.js#L84
;; Maybe also:
; (.. system -meta -props)
[:input (dissoc props :__scTheme :theme :control :size :valid)])))
(r/render [:> Input {:as r-input ...}] container)
```