Pull to refresh

React.lazy? Но что если у вас не компонент?

Reading time 3 min
Views 10K
Этот code splitting, честное слово, уже немного надоел. Мы все ходим и ходим по кругу, и в этом и есть главная проблема.

Code splitting начинался как разделение на уровне Модулей, а закончился как разделение на уровне Компонент.

И проблема тут исключительно в голове — React.lazy это хорошо, но и import никуда не делся… Так почему же code splitting только про компоненты?

React.lazy, React-Loadable, Loadable-Components, Imported-component — на свете много библиотек, которые оборачивают загрузку модуля в некий сахар, исключительно чтобы немного более user-friendly обработать загрузку компонента и показать его по готовности. Минимальный код для «async-loader».

const loadable = (loaderFunction) => 
    class AsyncComponent extends React.Component {
        state = { ResultComponent: null, error: false, };

        componentWillMount() {
            loaderFunction
              .then(result => this.setState({ ResultComponent: result.default || result})) // "es6" default export
              .catch(() => this.setState({ error: true }); 
        }

        render() {
            const { error, ResultComponent } = this.state;    
            // Display loaded component
            return ResultComponent
                 ? <ResultComponent {...this.props}/>
                 : (error ? <ErrorComponent /> : <LoadingComponent />)
        }
    }

Suspense и React.lazy просто другой вариант работы со стейтом. Ничего более.

Но что делать если у вас не компонент?


Проблемы с этим вроде бы нет — import(«someStuff»).then('go-on'). Но тут опять начинаются вопросы про то как это правильно разместить в lifecycle Reactа, что делать есть промис заресолвился после смерти компонента, и так далее. И всех в голове одни компоненты.

Я провел мини опрос — НИКТО более не использует этот, самый древний, вариант code splitting. Не знает как его кушать в современных условиях. И в общем все плохо.
При этом решение есть, и опять же в 4 строчки — renderProps

Все очень просто — не смотря на то, что обьектом code splitting будет не Компонент а Модуль — местом совершения операции всеравно будет Компонент.

const loadableModule = (loaderFunction) => 
    class AsyncComponent extends React.Component {
        state = { ResultComponent: null, error: false, };

        componentWillMount() {
            loaderFunction
              .then(result => this.setState({ module: result.default || result})) // "es6" default export
              .catch(() => this.setState({ error: true }); 
        }

        render() {
            const { error, module } = this.state;    
            return module
                 // pass it as a render prop!
                 ? this.props.children(module) 
                 // pass it as a render prop!
                 : (error ? <ErrorComponent /> : <LoadingComponent />)
        }
    }

Тот же самый паттерн, только повернутый в сторону загрузки кода и «предоставления» этого кода как renderProps.

Работает из коробки:


  • loadable-components (loadable.lib)

    import loadable from '@loadable/component'
    const Moment = loadable.lib(() => import('moment'))
    function FromNow({ date }) {
      return (
        <div>
          <Moment fallback={date.toLocaleDateString()}>
            {({ default: moment }) => moment(date).fromNow()}
          </Moment>
        </div>
      )
    }
    
  • react-lodable (react-loadable-library)

    import {importedLibraryDefault} from 'react-loadable-library';
    const Moment = importedLibraryDefault( () => import('momentjs'));
    <Moment>
     { (momentjs) => <span> {momentjs(date).format(FORMAT)}</span> }
    </Moment>
    
  • react-imported-component (react-imported-library)

    // интерфейсно совместим с react-loadable-library, плюс поддержка Suspense
    

Дешево, и очень сердито. Мне это позволило срезать дополнительные 20%. Но, главное, позволило очень декларативно настроить code-splitting, который будет загружать только то, что надо, и когда надо.

Теперь твой ход, %username%.
И кто перепишет это на hooks?
Tags:
Hubs:
+15
Comments 52
Comments Comments 52

Articles