Can you wrap the body of the let in a (fn [] body)
People were asking about Framer-motion hera and on Github so I tested it with Reagent and at least this simple case works: https://github.com/reagent-project/reagent/compare/framer-motion-example
Can anyone help me understand how to translate a component like this into a reagent one?
import ReactMarkdown from 'react-markdown';
import MathJax from 'react-mathjax';
import RemarkMathPlugin from 'remark-math';
function MarkdownRender(props) {
const newProps = {
...props,
plugins: [
RemarkMathPlugin,
],
renderers: {
...props.renderers,
math: (props) =>
<MathJax.Node formula={props.value} />,
inlineMath: (props) =>
<MathJax.Node inline formula={props.value} />
}
};
return (
<MathJax.Provider input="tex">
<ReactMarkdown {...newProps} />
</MathJax.Provider>
);
}
export default MarkdownRender
I specifically don't quite know how to handle the renderers
and with the return
statement.
I always have the hardest time figuring out any kind of direct React interop in any non-trivial case.
The examples consist mostly of like [:> ReactComponent]
and whee you're done.
(defn markdown-render [props]
[:> (.-Provider MathJax)
{:input "text"}
[:> ReactMarkdown
(merge props
{:plugins [RemarkMathPlugin]
:renderers (merge (:renderers props)
{:math (fn [js-props]
(r/as-element [:> (.-Node MathJax) {:formula (.-value js-props)}]))
:inlineMath (fn [js-props]
(r/as-element [:> (.-Node MathJax) {:inline true :formula (.-value js-props)}]))})})]])
@juhoteperi Thank you so much. Let me give this a try.
...
is just into
or merge
, not really React specific. Only gotcha is to use as-element
or reactify-component
or such with function in the props that need to return React elements
As hiccup syntax within the function is not autoamtically converted by Reagent
And note that props
argument for those renderers is the js object
There are 3 main things one has to understand in order to painlessly interop with React components - A difference between components, instances, and elements - When and how Reagent converts CLJS data structures into JS ones and vice versa - How exactly the props you pass to the underlying React components will be used Maybe I'm forgetting something - let me know.
@juhoteperi So in that case, how do you use markdown-render
? What has to be in props?
markdown-render props is cljs map
@p-himik Yeah, despite having used reagent itself for a few years now, I don't have a great understanding of those things, unfortunately.
Wow, it works!
Now I just have to dig into this example to really understand it.
:>
is unfortunately not very clear on what it converts. :r>
or create-element
is more obvious as you have to convert everything to JS objects yourself.
With :r>
and create-element
it could look like this:
(defn markdown-render [props]
[:r> (.-Provider MathJax)
#js {:input "text"}
[:> ReactMarkdown
(clj->js (merge props
{:plugins #js [RemarkMathPlugin]
:renderers (clj->js (merge (:renderers props)
{:math (fn [js-props]
(r/create-element (.-Node MathJax) #js {:formula (.-value js-props)}))
:inlineMath (fn [js-props]
(r/create-element (.-Node MathJax) #js {:inline true :formula (.-value js-props)}))}))}))]])
So the fundamental things I got wrong was:
1. not calling as-element
on my return values from the renderers
2. Not knowing how to express "MathJax.Node" (for example) as (.-Node MathJax)
.
I didn't even know :r>
existed!!!!
Just in latest 1.0.0-alpha2
It is probably only mentioned in the changelog and the issue
@juhoteperi Thanks again for your help. If I ever run into you at a clojure conference, I owe you the drink of your choice. 🙂