Fork me on GitHub
#reagent
<
2022-11-05
>
Sam Ritchie03:11:07

hey all - how can I pass a property on to a component with a - intact? I am passing :fonts-directory and reagent seems to be passing it along as fontsdirectory. an underscore will survive, but not a dash

Sam Ritchie03:11:20

[:math-field {:ref js/console.log
               :fonts-directory ""}
  "face" " cake"]

Sam Ritchie03:11:21

wait - forgot we’re on the pro plan and searched. I’m set! (using a string works)

Sam Ritchie21:11:19

Question… when a component in react like textarea doesn’t re-render on a change to some property like defaultValue, how is it doing that? I am writing a component that is a light wrapper over a textarea-like thing and want to make sure that it behaves this way too. The underlying thing is a “math-field”, so I need to reimplement the value / defaultValue pair of keys and their behavior.

Sam Ritchie21:11:34

Currently using function components and hooks

lilactown03:11:00

a lot of it is specific to the way React interacts with the DOM. I'm not sure that how React implements textarea is actually relevant to what you're doing

Sam Ritchie04:11:50

Fair - maybe a better question is, what way would you recommend for making a component where some property does not trigger a re render even if changed

timothypratley06:11:41

Hi Sam, AFAIK defaultValue is a regular HTML attribute (https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement), If you modify it, the element does not visually change. I believe that react/reagent "re-render" still happens, the difference in the dom is detected, and the defaultValue is updated to the new value, but the new value has no effect. Sorry if that seems pedantic, but I think it's important to point out that the attribute is "non-reactive" by HTML behavior more than anything in react/reagent. So to answer your question more directly, you could create a component that takes an initial input but will never change the dom on updated inputs by doing something like:

(defn widget [message]
  (let [actual-message message]
    (fn [message]
      [:div actual-message])))
^^ This will use the input during construction, but then ignore the input on future renders. Re-renders will still occur but they will be effectively a no-op, as nothing changed. (You could do a similar thing in with-let or using the component form). Hope that helps, sorry if I'm way off

lilactown17:11:45

@U017QJZ9M7W I guess I'm also confused about "does not trigger a re render even if changed." I think that could be the wrong way to think about it. Could you explain the behavior you want? e.g. "When I pass in the default-value prop to the text input, it uses that as the value on first render, and then any changes to it do not change the value of the text input." Also, what have you tried so far? Are you having some specific issues trying to implement the behavior you want? ATM the question is very general, and it sounds like there might be more details both to the behavior you want and the technical implementation - e.g. it sounds like you might be using either a third party library ("text area-like thing") or you're building a complex component yourself. To try and answer your original question, though, you can avoid re-rendering a component by memoizing it. See the React docs on React.memo and React.useMemo. These can be used to control when certain computations happen, including the re-creation of elements that React uses to determine whether any changes to the page must happen. I think what you might actually want though is a higher level pattern: to initialize some internal state in your component and then have the component be either "uncontrolled" (i.e. the component has internal state determining its display & behavior that doesn't react to outside changes) or "controlled" (i.e. the component's state is external to it, props passed to it determine its display & behavior). Memoization & avoiding renders might be the way to do this, but IME probably not; if you're avoiding re-renders, it's usually either for performance reasons OR you're doing some weird mutable DOM manipulation (likely wrong). So that's why it's useful to know exactly what you're trying to do, as implementing this pattern of toggling between either "controlled" or "uncontrolled" can be tricky in practice.

Sam Ritchie17:11:44

I’ll respond today with details here!

1
Sam Ritchie17:11:06

Busy Sunday with the kiddos, thanks for all the responses

🌅 1
lilactown17:11:00

I'm in no rush 😄

lilactown17:11:12

I'm enjoying a lazy Sunday morning myself

Sam Ritchie02:11:59

@U4YGF4NGM my question was vague; I am wrapping a math-field web component from this library: https://cortexjs.io/mathlive/demo/, and just like a textarea it takes children. what saved me here was that I realized that it treats its single string child like a defaultValue, so I can 1. pass along (or default-value value "") from my top-level component, and then 2. use a hook that triggers on changes to my value property to call .setValue on the MathfieldElement reference.

1
Sam Ritchie02:11:41

@U4YGF4NGM here is what I have so far (don’t treat the code comments as final, this is all coming together now!) https://gist.github.com/sritchie/aabc0895ac6c831f379a0212265cc9d8