react-truncate-markup: Error: Maximum update depth exceeded
I can’t ever seem to get past this error:
Currently the library seems unusable =/ Not sure how to guard against it within the componentDidUpdate
lifecycle hook.
About this issue
- Original URL
- State: open
- Created 6 years ago
- Reactions: 4
- Comments: 22 (9 by maintainers)
hi @patrik-piskay ,
Here is the test data I used to replicate the issue:
The issue with refs is that it returns actual DOM nodes instead of React elements. So instead of
we get
That means we’d need to transform the returned DOM nodes back into React elements again (or any tree structure so we can truncate it and have it rendered again), which might be doable, but again not reliable. For example, I don’t think events (click etc.) would work. Also, we’d lose access to any React components after the initial render (because we’d continue working with the initially returned DOM elements), so any effects happening in their lifecycle methods would be lost.
It’s probably best to keep it simple for now and use DOM elements only. For the future, who knows, maybe with Hooks there will be something we can do to support React components, I’ll keep my eyes on it.
So here is what I found out…
Issue:
react-truncate-markup
doesn’t support React components as its children. Not just HOC/render props as mentioned in https://github.com/parsable/react-truncate-markup/issues/12#issuecomment-430308275, but all components.Solution: tl;dr: there is none that I am aware of that works for every case, so in dev mode we’ll warn if React components are used as
<TruncateMarkup />
children and skip any truncation, displaying the whole content instead.<TruncateMarkup />
will work fine when using inlined DOM elements only.I’ve spent a few hours trying to get React components (both classes and functions) to work. The reason it’s not trivial is because of the way the truncate functionality works here. General approach is to take the whole element tree structure (
props.children
of the parent component) and work with that. This tree might look like this:↓↓↓
which is easy to work with as we have the whole final “render” tree available, which means we can potentially end up with this result (after truncation):
But if we were to move a part of the tree to a separate component, it could look like this:
↓↓↓
which hides what’s getting rendered in
<Person />
so we cannot use that in the current truncation algorithm. We could truncate only afterHello
or afterHello <span>{person}</span>
, but we’d never be able to truncate anything inside the<span>{person}</span>
because it’s not initially visible to us, only after React renders it into the DOM.One idea I had to solve this was to “unwrap” the whole tree before starting any truncation work by “evaluating” these nested components:
This actually worked and I was able to get nested components to work, until…it didn’t.
Some components I used for testing used context, which this approach didn’t support. Even before trying this approach I felt it’s probably not the best idea to start emulating React itself by rendering the tree on our own, and when I experienced the context issues, I decided it’s (probably) nothing we can solve reliably, so the best thing we could do is to officially not support it - we’ll warn if React components are detected in the
<TruncateMarkup />
children and will skip any truncation work, rendering the whole content instead.<TruncateMarkup />
will continue to work fine when using inlined DOM elements as its children like in the original case: