Markdown formatting & small fixes

This commit is contained in:
Juho Teperi 2019-04-26 13:12:35 +03:00
parent 901607c45f
commit 96f090b991
1 changed files with 46 additions and 29 deletions

View File

@ -1,10 +1,13 @@
# Interop with React # Interop with React
A little understanding of what reagent is doing really helps when trying to use React libraries and reagent together. A little understanding of what Reagent is doing really helps when trying to use
React libraries and reagent together.
## Creating React Elements directly ## Creating React Elements directly
The `reagent.core/create-element` function simply calls React's `createElement` function (and therefore, it expects either a string representing an HTML element or a React Component). The `reagent.core/create-element` function simply calls React's `createElement`
function (and therefore, it expects either a string representing an HTML
element or a React Component).
As an example, here are four ways to create the same element: As an example, here are four ways to create the same element:
@ -28,20 +31,33 @@ As an example, here are four ways to create the same element:
[:div.foo "Hello " (r/create-element "strong" [:div.foo "Hello " (r/create-element "strong"
#js{} #js{}
"world")]]) "world")]])
(defn mount-root [] (defn mount-root []
(reagent/render [integration] (reagent/render [integration]
(.getElementById js/document "app"))) (.getElementById js/document "app")))
``` ```
This works because `reagent/render` itself expects (1) a React element or (2) a Hiccup form. If passed an element, it just uses it. If passed a Hiccup, it creats a (cached) React component and then creates an element from that component. This works because `reagent/render` itself expects (1) a React element or (2) a
Hiccup form. If passed an element, it just uses it. If passed a Hiccup, it
creats a (cached) React component and then creates an element from that
component.
## Creating React Elements from Hiccup forms ## Creating React Elements from Hiccup forms
The `reagent.core/as-element` function creates a React element from a Hiccup form. In the previous section, we discussed how `reagent/render` expects either (1) a Hiccup form or (2) a React Element. If it encounters a Hiccup form, it calls `as-element` on it. When you have a React component that wraps children, you can pass Hiccup forms to it wrapped in `as-element`. The `reagent.core/as-element` function creates a React element from a Hiccup
form. In the previous section, we discussed how `reagent/render` expects either
(1) a Hiccup form or (2) a React Element. If it encounters a Hiccup form, it
calls `as-element` on it. When you have a React component that wraps children,
you can pass Hiccup forms to it wrapped in `as-element`.
## Creating Reagent "Components" from React Components ## Creating Reagent "Components" from React Components
The function `reagent/adapt-react-class` will turn a React Component into something that can be placed into the first position of a Hiccup form, as if it were a Reagent function. Take, for example the react-flip-move library and assume that it has been properly imported as a React Component called `FlipMove`. By wrapping FlipMove with `adapt-react-class`, we can use it in a Hiccup form: The function `reagent/adapt-react-class` will turn a React Component into
something that can be placed into the first position of a Hiccup form, as if it
were a Reagent function. Take, for example the react-flip-move library and
assume that it has been properly imported as a React Component called
`FlipMove`. By wrapping FlipMove with `adapt-react-class`, we can use it in a
Hiccup form:
```clojure ```clojure
(defn top-articles [articles] (defn top-articles [articles]
@ -51,7 +67,8 @@ The function `reagent/adapt-react-class` will turn a React Component into someth
articles] articles]
``` ```
There is also a convenience mechanism `:>` (colon greater-than) that shortens this and avoid some parenthesis: There is also a convenience mechanism `:>` (colon greater-than) that shortens
this and avoid some parenthesis:
```clojure ```clojure
(defn top-articles [articles] (defn top-articles [articles]
@ -87,11 +104,16 @@ The `reagent/reactify-component` will take a Form-1, Form-2, or Form-3 reagent "
Note: Note:
* `adapt-react-class` and `reactify-component` are not perfectly symmetrical, because `reactify-component` requires that the reagent component accept everything in a single props map, including its children. * `adapt-react-class` and `reactify-component` are not perfectly symmetrical,
because `reactify-component` requires that the reagent component accept
everything in a single props map, including its children.
## Example: "Decorator" Higher-Order Components ## Example: "Decorator" Higher-Order Components
Some React libraries use the decorator pattern: a React component which takes a component as an argument and returns a new component as its result. One example is the React DnD library. We will need to use both `adapt-react-class` and `reactify-component` to move back and forth between React and reagent: Some React libraries use the decorator pattern: a React component which takes a
component as an argument and returns a new component as its result. One example
is the React DnD library. We will need to use both `adapt-react-class` and
`reactify-component` to move back and forth between React and reagent:
```clojure ```clojure
(def react-dnd-component (def react-dnd-component
@ -100,7 +122,7 @@ Some React libraries use the decorator pattern: a React component which takes a
(decorator (reagent/reactify-component top-level-component))))) (decorator (reagent/reactify-component top-level-component)))))
``` ```
This is the equivalent javascript: This is the equivalent JavaScript:
```clojure ```clojure
import HTML5Backend from 'react-dnd-html5-backend'; import HTML5Backend from 'react-dnd-html5-backend';
@ -115,7 +137,7 @@ export default DragDropContext(HTML5Backend)(TopLevelComponent);
## Example: Function-as-child Components ## Example: Function-as-child Components
Some React components expect a function as their only child. React autosizer is one such example. Some React components expect a function as their only child. React AutoSizer is one such example.
```clojure ```clojure
[(reagent/adapt-react-class AutoSizer) [(reagent/adapt-react-class AutoSizer)
@ -127,13 +149,23 @@ Some React components expect a function as their only child. React autosizer is
## Getting props and children of current component ## Getting props and children of current component
Because you just pass arguments to reagent functions, you typically don't need to think about "props" and "children" as distinct things. But Reagent does make a distinction and it is helpful to understand this, particularly when interoperating with native elements and React libraries. Because you just pass arguments to reagent functions, you typically don't need
to think about "props" and "children" as distinct things. But Reagent does make
a distinction and it is helpful to understand this, particularly when
interoperating with native elements and React libraries.
Specifically, if the first argument to your Reagent function is a map, that is assigned to `this.props` of the underlying Reagent component. All other arguments are assigned as children to `this.props.children`. Specifically, if the first argument to your Reagent function is a map, that is
assigned to `this.props` of the underlying Reagent component. All other
arguments are assigned as children to `this.props.children`.
When interacting with native React components, it may be helpful to access props and children, which you can do with `reagent.core/current-component`. This function returns an object that allows you retrieve the props and children passed to the current component. When interacting with native React components, it may be helpful to access
props and children, which you can do with `reagent.core/current-component`.
This function returns an object that allows you retrieve the props and children
passed to the current component.
Beware that `current-component` is only valid in component functions, and must be called outside of e.g event handlers and `for` expressions, so its safest to always put the call at the top, as in `my-div` here: Beware that `current-component` is only valid in component functions, and must
be called outside of e.g. event handlers and `for` expressions, so it's safest
to always put the call at the top, as in `my-div` here:
```clojure ```clojure
(ns example (ns example
@ -151,21 +183,6 @@ Beware that `current-component` is only valid in component functions, and must b
[:p "Some other text in bold."]]]) [:p "Some other text in bold."]]])
``` ```
## React Interop Macros
**Please do not use these macros. They will be removed at some point. Either use extern inference, externs or proper `goog.object/get`.**
Reagent provides two utility macros `$` and `$!` for getting and setting javascript properties in a way that is safe for advanced compilation.
`($ o :foo)` is equivalent to `(.-foo o)`
`($ o foo arg1 arg2)` is the same as `(.foo o arg1 arg2)`
Similarly,
`($! o :foo 1)` is equivalent to `(set! (.-foo o) 1)`
Note, these are not necessary if your JavaScript library has an externs file or if externs inference is on and working.
## Examples ## Examples
- [Material-UI](../examples/material-ui/src/example/core.cljs) - [Material-UI](../examples/material-ui/src/example/core.cljs)