Problems encountered
Try to get the height value of the outer element in useEffect, but it is always smaller than the real value
useEffect(() => {
console.log(contentRef.current.clientHeight)
},[mdHtml,contentLoading])
{ contentLoading ? <div className="content__loading"><Spin /></div> : <div className="content__body markdown-body" onClick={handleContentClick} ref={contentRef} dangerouslySetInnerHTML={{ __html: mdHtml }} />}
Copy the code
I guess there are a lot of images in mdHtml, and the images are not fully loaded, so I added promise to test them
const imgLoadFinish = () => { const promiseAry = []; const imgs = [...contentRef.current.querySelectorAll('img')]; imgs.forEach((img, i) => { promiseAry[i] = new Promise((resolve) => { img.onload = () => { resolve(img); }; }); }); Promise.all(promiseAry).then(() => { createWaterMark(); }); }; useEffect(() => { if (mdHtml && ! contentLoading) { imgLoadFinish(); } }, [mdHtml, contentLoading]);Copy the code
Once the image is loaded, you can get the correct height in createWaterMark
UseEffect is executed after layout and drawing:
Have the images not been loaded at this time? So what is the order in which the browser renders a page? With a question to find the relevant article, summarized as follows
The process of rendering a page by the browser
Build a Dom Tree
The back end returns the HTML page, and the browser builds the DOM Tree (from Json-> Token -> node -> DOM Tree). During the building process, if there are resources such as image CSS, the request will be made, but it will not block the page to continue rendering
Build Css Tree
Load the CSS and build a CSS Tree
Build Render Tree
When you combine CSS and DOM and build a Render Tree, it does not Render to the page, but just uses the Render Tree to determine the layout of the page (i.e. where elements are on the page and what size elements are)
1) Adding and deleting elements (including inserting subsequent requested image resources)
2) Change the box model
draw
Once the Render Tree has built and started the layout, you can draw the Render Tree (element colors, fonts, etc.) onto the page, where changes only cause partial changes to the page
Related resources:
Developer.mozilla.org/en-US/docs/… Developer.mozilla.org/zh-CN/docs/…
Summary: This is done because the browser runs single-threaded, and it is best not to block the main thread at the same time.
Going back to the previous problem, requests for resources such as images may not be completed after the browser has finished layout and drawing, so the true height of the element cannot be obtained at this point
Conclusion:
- React’s rendering mechanism follows the rendering process of the browser. When rendering a page, the browser builds a DOM tree first. If images or other resources are encountered, the building will continue
- Because the browser is single-threaded, so for some of the data acquisition, best asynchronous or sequential execution, so need componentDidMount/function useEffect life cycle.
Follow-up:
This solution can cause other problems, such as the inability to display the entire page when an image fails to load, and the slow initialization of the page
The solution is to set the initialization state of the image to false and get the height of the parent element. UseEffect listens for the state of the image. When the image is loaded, the height of the image is obtained again