splincodewd
@splincodewd
Developer

Можно ли на ReactJS динамически загружать компоненты без знания о них при сборке самого приложения (как это реализовано в Angular 2+)?

Всем здравствуйте, помогите пожалуйста решить проблему, хотя помочь в поиске.

Есть задача:
* разработчики разрабатывают компоненты (предположим на реакте)
* затем они подкладывают в dist директорию скомпилированный компонент
* в базе указывают, что есть такой то компонент
* после чего, когда в браузере инициализируется приложение
* запрашивает на сервере какие компоненты отображает ему и загружает асинхронно anything-1.component.js, .. N
* и легко отрисовывает все компоненты и связывает данные

Сам я на React ничего не писал (один только helloWorld написал однажды), пишу в основном на Angular

Но после первого ng, я понял, что они перестарались. Для того, чтобы там загружать динамически компоненты, чтобы создалась фабрика компонента с его шаблонам, там типо нужно указывать для рутового модуля entryComponents, но тут проблема же в том, что тебе нужно указывать все компоненты какие ты хочешь динамически отобразить, а если я в браузере не знаю какие именно, получается я указывают (все свои 10 тысяч компонентов для entryComponents в качестве ссылок), ну это же глупое решение, к тому же, если я разработаю новый компонент, мне придется заново пересобирать свое приложение (через webpack или еще что).

Что не устраивает, что нужно указывать все компоненты, которые у меня есть, и это реализовано в Angular, Карл... Первый Angular был написан на чистом javascript, но там все глобально, в любой момент, я мог асинхронно загрузить свой скрипт (который был бы Angular контроллером с шаблонами) и все это у меня заработало, если бы я подключил к angular.module новый контроллер, а теперь так и только при сборке.

@NgModule({
  imports: [...],
  declarations: [...],
  entryComponents: [
    Anything1Component,
    ...,
    AnythingNComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }


Подскажите, умеет ли загружать компоненты реакт, или еще какие фреймворки, чтобы не нужно было париться над такими вещами, которые в Angular присутствуют, ведь Angular генерируется у меня из TypeScript посредством Webpack и там такая каша в скомпилированном коде, что даже не знаешь уже как обертку свою написать.

На чистом javascript было бы больше возможностей (хоть на jQuery пиши), но проблема уже в читаемости и распространении для других разработчиков, а ведь хочется простой data-binding и прочее удобное ООП в совокупности с твоим веб-приложением.

Спасибо.
  • Вопрос задан
  • 1041 просмотр
Решения вопроса 3
@davidnum95
гуглить react async load components
Ответ написан
Динамически подгружать компоненты? Это не к реакту, это к вашему сборщику.
В последних вебпаках (2+) есть поддержка динамических импортов:

import('moduleName').then(module => /* do something */)


Ну и дальше вы сможете сохранить этот модуль (например в state):
class Bundle extends Component {
  state = {
    // short for "module" but that's a keyword in js, so "mod"
    mod: null
  }

  componentWillMount() {
    this.load(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.load !== this.props.load) {
      this.load(nextProps)
    }
  }

  load(props) {
    this.setState({
      mod: null
    })
    props.load((mod) => {
      this.setState({
        // handle both es imports and cjs
        mod: mod.default ? mod.default : mod
      })
    })
  }

  render() {
    return this.state.mod ? this.props.children(this.state.mod) : null
  }
}

export default Bundle


А вызывать все это дело вот так:
<Bundle load={() => import('./something')}>
  {(mod) => ()}
</Bundle>


Но это все в рамках проекта - добавили новый компонент - пересобрали проект. И это самая адекватная (на мой взгляд) практика. Случаи, конечно, бывают разные - но мне как-то уютнее, когда я знаю, что весь нужный код находится у меня в проекте, а не где-то там. Я имею ввиду в первую очередь зависимости ваших динамических компонентов (в первом ангуляре была своя система DI и свой подход к разработке, но с тех пор уже много воды утекло и нативные JS модули, очевидно, гораздо лучшее решение). Конечно, теоретически - можно напридумывать костылей и грузить их откуда угодно...
Ответ написан
@montecazazza
Node, GraphQL, React
Это называется code splitting - фича включена в Webpack 2. инструкция import стала асинхронная. Можно сделать HOC (asyncComponent) и использовать его для удобства (обычно код делят по раутам).
Потребуется настроить Webpack соответствующим образом, чтобы делил код по частям (chunks). В общем ищите по "code splitting React", кто ищет тот найдет

Вот asyncComponent в самом простом варианте
import React, { Component } from 'react';

export default function asyncComponent(importComponent) {
  return class AsyncComponent extends Component {
    constructor(props) {
      super(props);
      this.state = { Component: null };
    }
    async componentDidMount() {
      const { default: Component } = await importComponent();
      this.setState({ Component });
    }
    render() {
      const { Component } = this.state;
      return Component && <Component {...this.props} />
    }
  }
}


Вот как он может быть использован с React Router 4
import React from 'react';
import { Route, Switch } from 'react-router-dom';

import { Wrapper } from 'Styles';
import SyncComponent from 'Components/SyncComponent';
import { asyncComponent } from 'Helpers';

const AsyncComponent = asyncComponent(() => import('Components/AsyncComponent'));

const App = () => (
  <Wrapper>
    <Switch>
      <Route path='/route-to-async/' component={AsyncComponent}/>
      <Route component={SyncComponent}/>
    </Switch>
  </Wrapper>
);
export default App;
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы