最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I do a synchronous ReactDOM.render - Stack Overflow

programmeradmin3浏览0评论

For my app, I need to render some children, and then measure the resulting div. In pseudo code, it would look something like this:

function getDims(child) {
    var testEl = document.getElementById('test-el');
    ReactDOM.render(child, testEl);
    var dims = testEl.getBoundingClientRect();
    ReactDOM.unmountComponentAtNode(testEl);
    return dims;
}

Unfortunately, according to the documentation ReactDOM.render may in the future bee asynchronous. Is there a future-proof option to force synchronous rendering so the above function will work?

For my app, I need to render some children, and then measure the resulting div. In pseudo code, it would look something like this:

function getDims(child) {
    var testEl = document.getElementById('test-el');
    ReactDOM.render(child, testEl);
    var dims = testEl.getBoundingClientRect();
    ReactDOM.unmountComponentAtNode(testEl);
    return dims;
}

Unfortunately, according to the documentation ReactDOM.render may in the future bee asynchronous. Is there a future-proof option to force synchronous rendering so the above function will work?

Share Improve this question asked Oct 29, 2016 at 12:27 derekdreeryderekdreery 3,9225 gold badges31 silver badges41 bronze badges 1
  • 1 I imagine you could use react-dom-server with renderToStaticMarkup or renderToString and insert that string into the DOM afterwards. Of course it's a bit sad to serialize into a string without the need for it. But if async isn't an option it may just work. – Fiona Runge Commented Feb 1, 2018 at 10:36
Add a ment  | 

3 Answers 3

Reset to default 5

You can pass a callback to ReactDOM.render(ReactElm, DOMNode, callback). The callback will be executed once the ReactElm gets loaded into the DOMNode.

Hope this helps!

function getDims(child) {
    var testEl = document.getElementById('test-el');
    ReactDOM.render(child, testEl, function(){
       var dims = testEl.getBoundingClientRect();
       ReactDOM.unmountComponentAtNode(testEl);
       return dims;
    }); 
}

Usage example:

class App extends React.Component{
  render(){ return <h1>Hello</h1>}
}
  
  ReactDOM.render(<App/>,
    document.getElementById('app'),
    () => console.log('Component Mounted'))
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

In React 18+, we can use renderToString:

    const view = renderToString(<div id="text-div-id">{text}</div>);

    const outerEl = document.getElementById('outer-div-id') as HTMLDivElement;
    outerEl.innerHTML = view;

    const textEl = document.getElementById('text-div-id') as HTMLDivElement;
    const bounding = textEl.getBoundingClientRect();

In React 18+, on the client you can use flushSync:

import { createRoot } from 'react-dom/client';
import { flushSync } from 'react-dom';

const div = document.createElement('div');
const root = createRoot(div);
flushSync(() => {
  root.render(<MyIcon />);
});
console.log(div.innerHTML); // For example, "<svg>...</svg>"

renderToString or renderToStaticMarkup are from react-dom/server and importing it on the client unnecessarily increases your bundle size and should be avoided.

+ Read More

发布评论

评论列表(0)

  1. 暂无评论