React – How to interact with DOM?

How to interact with a HTML element in React?

Use useRef

  • Embed HTML content
import { useRef, useEffect } from 'react'

const TestComponent = () => {
  const rootDiv = useRef(null)

  useEffect(() => {
    const root = rootDiv.current
    root.innerHTML = `<span>Hello</span>`
  }, [])

  return <div ref={rootDiv}></div>
}

export default TestComponent
  • Focus an editable div element
import { useEffect, useRef, useState } from 'react'

const Note = () => {
  const [isEditable, setEditable] = useState(false)
  const contentDiv = useRef(null)

  useEffect(() => { // After UI is updated
    if (isEditable) {
      const refContentDiv = contentDiv.current
      refContentDiv.focus()
    }
  }, [isEditable])

  function onEditNote() {
    setEditable(true) // Schedule for UI update
  }

  function onSaveNote() {
    setEditable(false) // Schedule for UI update
  }

  return (
    <>
      {isEditable ? (
        <div onClick={onSaveNote}>
          Save Note
        </div>
      ) : (
        <div onClick={onEditNote}>
          Edit Note
        </div>
      )}
      <div
        ref={contentDiv}
        contentEditable={isEditable}
      >
        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusm od
        tempor incidi dunt ut labore et dolore magna aliqua. Ut enim ad minim
        veniam, quis nostrud exercitation
      </div>
    </>
  )
}

export default Note

How to render a React component into a DOM element?

  • HTML file
<!DOCTYPE html>
<html lang="en">

<body>
   <div id="id-component-test"></div>
</body>

</html>
  • React component
import ReactDOM from 'react-dom'

const TestComponent = () => {
  ...
}

ReactDOM.render(<TestComponent />, document.getElementById('id-component-test'))

How to style a component having content of an external HTML file (url)?

  • Get html source code
export const fetchHtmlUrl = async (htmlUrl: string) => { // htmlUrl = https://xxx.xx/abc.html
  const { data } = await axios.get(htmlUrl)
  return data
}
import { useRef, useEffect } from 'react'
import { fetchHtmlUrl } from 'src/network/restful/restApi'
import { useQuery } from 'react-query'
import './index.scss'

const TestComponent = ({ htmlUrl }) => {
  const { data, isLoading } = useQuery(['fetchHtmlUrl', htmlUrl], () =>
    fetchHtmlUrl(htmlUrl)
  )

  const rootDiv = useRef(null)
  useEffect(() => {
    if (!data) {
      return
    }
    const root = rootDiv.current
    root.innerHTML = data.trim()
  }, [data])

  if (isLoading) {
    return null
  }

  return <div ref={rootDiv} className='test-component'></div>
}

export default TestComponent
  • Create css file to style the page
// index.scss

.test-component {
  line-height: 1.4em;
  color: #666;
  -webkit-font-smoothing: antialiased;

  h1, h2, h3, h4, h5, h6 {
    line-height: 1.4em;
    color: #666;
  }

  h1 {
    font-weight: 300;
  }

  ...
}

How to render custom iframe in React?

const TestComponent = ({ }) => {

  ////////////////////////////
  // Define iframe reference
  const iframeRef = useRef(null);

  useEffect(() => {
    const iframe = iframeRef.current;
    let timer;
    
    if (!iframe) {
      return;
    }

    timer = setTimeout(() => {
      const win = iframe.contentWindow;

      ////////////////////////////////////
      // Communicate with iframe content
      win.addEventListener('message', (event) => {
        switch (event.data?.type) {
          case 'exitFullscreen':
            // do something;
            break;
          default:
        }
      });

      //////////////////
      // Inject style 
      const doc = win.document;
      const { body } = doc;
      const style = doc.createElement('style');
      style.innerHTML = `
        html, body { width: 100%; height: 100%; }
        body { margin: 0; background: #000000; overflow: hidden; }
        ...
        @media only screen and (max-width: 629px) {
          .video-js:not(.vjs-has-started) .vjs-tech {
            opacity: 0.4!important;
          }
        }`;
      body.appendChild(style);

      //////////////////////////
      // inject a HTML element
      const video = doc.createElement('video');
      video.className = 'video-js vjs-fluid';
      video.setAttribute('one-attribute', 'some-value');
      body.appendChild(video);

      //////////////////////////
      // inject script element
      const bcScript = doc.createElement('script');
      bcScript.src = `https://xxxxx.xx/abcd.js`;
      bcScript.onload = () => {
        // do something ...
      };

      body.appendChild(bcScript);
    }, 100);

    return () => {
      iframeRef.current = null;
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, []);

  return (
    <iframe allowFullScreen={false} ref={iframeRef} />
  );
};

export default TestComponent;

Useful DOM APIs

  • Select all elements having a class name
    • [id^=’someId’]: match all ids starting with someId
    • [id$=’someId’]: match all ids ending with someId
    • [id*=’someId’]: match all ids containing someId
  const elements = document.querySelectorAll(
    'div[class*="contain-a-class"]'
  )

Be the first to comment

Leave a Reply

Your email address will not be published.


*