math
math

Reputation: 187

Count of Component in the page conceptual recursive problem

I have this conceptual problem and I have a really simple and minimal codesandbox for it:

I want to keep a count of the components that are rendered in my page (per component). These are my components. (I'm working with Preact but we're really talking about functions here)

function Element() {
  return " " //I'm not important
}
function Container() {
    //container is repeating my Element
    return <div>
            <Element />
            <Element />
            <Element />
            <Element />
           </div>   
}

I keep the count of Element and Container in the page with an High Order Function that keeps track of the count by adding a property to the component only if it's the first one (firstType = true).

I wanna do this because this type of component needs to render differently the first time. (< defs> for svg)

I can do that easily with this High Order Function

function Counter(Component) {
  let count = 0;
  return function (...props) {
   //this is for the purpose of the debugging
    return <>{++count} <Component {...props[0]} /> </>
  }
}

The problem occured when in another HOC I tried to render the component with renderToStaticString(),

P.S. I need to that on my Component so I can know its width and height (I could do this also with a ref to the dom node and a getBBox call but I want my application to work without a browser).

My best option would be converting the component to a string, getting the points of the path and then measure the path with PathCommander's server-side getBBox or maybe some other ssr techniques like PhantomJS.

This would all work relly nice but again when I run renderToStaticString on my component, the component itself gets also called by renderToStaticString and therefore the Counting HOC gets involved in it ruining the count of the components I had).

This is because this time, when I'm calling my component function, I'm calling it only to measure the path on the fly, not to render the component into the page like I would have done with a normal React.render() or in a normal ssr rendering situation. So I need to reset the count to 0 after doing this render on the fly. SO on the page it will still act correctly but I tried everything with no luck.

I seriously can't think of a simple and correct solution that would solves this puzzle all togheter, if anyone has some starting ideas or some useful infos please SHARE IT! Here I also did a codesandbox where you can play with (just uncomment the //renderToStaticString to make it stop working (You have to manually reload or autosave won't reset the count to 0 (this is because it's not ssr here ofc).

Upvotes: 0

Views: 151

Answers (1)

よつば
よつば

Reputation: 527

One technique might be to create a reference React.createElement and override it with a wrapper function that increments an elementCount.

function App() {
  return <div>
    <p>Hello world</p>
    <p>Another paragraph and <span>here</span></p>
    <p>This is the sixth element, counting the outermost App</p>
  </div>
}

let elementCount = 0
const createElement = React.createElement
React.createElement = (...args) => {
  elementCount++
  return createElement(...args)
}

ReactDOM.render(<App/>, document.querySelector("#app"))
console.log("total elements", elementCount)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>

total elements 6

This counts six (6) elements.

  1. <App>
  2. <div>
  3. <p>Hello world
  4. <p>Another paragraph and
  5. <span>
  6. <p>This is the sixth...

Not sure if it will work with renderToStaticString or not. Try it and let us know.

Upvotes: 1

Related Questions