2
votes

I wondering if it would be possible to use React 16's lazy, Suspense, createRef and forwardRef features together in order to attach a reference to a dynamically imported component. Does anyone know if this is possible. I tried to follow the example (https://github.com/facebook/react/pull/13446/commits/4295ad8e216e0747a22eac3eed73c66b153270d4#diff-e7eafbb41b012aba463f5a2f8fc00f65R1614), however it doesn't quite seem to work with dynamically imported components.

I have been able to get similar desired behavior by setting custom props in the parent component, passing it down to the child component and then setting the ref to that prop in the child's render function(Example below). My only issue with this approach is that it may not be the cleanest solution and it may be difficult to keep the implementation consistent across a large team. It will also make it easier when attempting to place the ref on the actual component.

// Working (Undesired implementation) // Parent.js

const LazyClass = lazy(() => { return import('./Child') };

class Parent extends React.Component {
    this.childRef = React.createRef();

    render() {
    return (
        <Suspense fallback={<div>Loading</div>}>
            <Child forwardRef={this.childRef} />
        </Suspense>
        );
    }

}

// Child.js

class Child extends React.Component {

    render() {
        return (<div>I am the Child!</div>);
    }

}

export default React.forwardRef(({forwardRef, ...props}/*, ref*/) => 
    <Child {...props} ref={forwardRef} />
);

////////////////////////////////////////////////////// // Desired Implementation with React.forwardRef()

//Parent.js

const LazyClass = lazy(() => { return import('./Child') };

class Parent extends React.Component {


    this.childRef = React.createRef();

    render() {
        return (
            <Suspense fallback={<div>Loading</div>}>
                <Child ref={this.childRef} />
            </Suspense>
        );
    }

}

// Child.js

class Child extends React.Component {

    render() {
        return (<div>I am the child</div>);
    }

}

export default React.forwardRef((props, ref) => 
    <Child { ...props } ref={ref} />
);

Setting the ref directly on a Lazily loaded component always returns null. It would be nice if it returned the value from React.createRef().

1

1 Answers

1
votes

The "ref as a props" approach is the smaller one but as you said you have to consider prop collision. The approach you linked is still correct. The test only changed slightly:

Update: Not sure if this was a bug previously but lazy now forwards refs automatically. Just be sure you export a component that can hold a ref.

See in action: https://codesandbox.io/s/v8wmpvqnk0