1

I have an IFrameComponent component, inspired by this post.

It looks basically like this :

class IFrameComponent extends React.Component {
    shouldComponentUpdate() {
        return false;
    }

    componentWillReceiveProps(nextProps) {
        if(this.props.content !== nextProps.content) {
            const html = getHTMLFromContent();
            const fdoc = this.iFrame.contentDocument;
            fdoc.write(html);
        }
    }

    render() {
        return (<iframe sandbox="..." ref={f => this.iFrame = f} />);
    }
}

Now that componentWillReceiveProps is considered unsafe, I'm trying to get rid of it.

The ways React advices to refactor componentWillReceiveProps are basically either to use static getDerivedStateFromProps or componentDidUpdate

Sadly, componentDidUpdate will never get called, because shouldComponentUpdate returns false (and I think this is fine ?) and I wouldn't be able to access this.iFrame reference in the static method getDerivedStateFromProps.

How would one refactor this code ?

falinsky
  • 7,229
  • 3
  • 32
  • 56
Logar
  • 1,248
  • 9
  • 17

1 Answers1

1

I think, One possible way is:

let iFrameRefs = {}

class IFrameComponent extends React.Component {
    static getDerivedStateFromProps (props) {
        if (iFrameRefs[props.id]) {
            const html = getHTMLFromContent();
            const fdoc = iFrameRefs[props.id].contentDocument;
            fdoc.write(html);
        }
        return null
    }

    shouldComponentUpdate() {
        return false;
    }

    render() {
        return (<iframe sandbox="..." ref={f => iFrameRefs[this.props.id] = f} />);
    }
}

Now from Parent Component pass unique id to each component. You can also manage id in IFrameComponent.

<IFrameComponent id='1' />
<IFrameComponent id='2' />
Mayank Shukla
  • 100,735
  • 18
  • 158
  • 142
  • Indeed, this works, although I don't feel very comfortable putting my refs outside of my object. Side note : in order to help future readers, could you add `if(iFrame && (props.content !== state.content))` and `return {content: props.content}` in `getDerivedStateFromProps`, in order to reflect the former `if(this.props.content !== nextProps.content)` ? – Logar Jun 14 '18 at 13:49
  • Sorry but I had to unaccept your answer because it has a major flaw : If the component is rendered multiple times by the parent, only one iFrame will be filled in by all the components :( – Logar Jun 14 '18 at 14:13
  • I realize my comment was not precise at all. What I meant was : If the parent component renders multiple instances of IFrameComponent, then all of these components will share the same IFrame reference. – Logar Jun 14 '18 at 14:36
  • yeah I thought of that solution too, it will work but does not feel right at all, does it ? – Logar Jun 14 '18 at 14:52