code

리액트 - 컴포넌트 동적 Import

starcafe 2023. 3. 19. 18:22
반응형

리액트 - 컴포넌트 동적 Import

사용자 입력에 따라 다른 컴포넌트를 렌더링하는 페이지가 있습니다.현재 아래와 같이 각 컴포넌트의 Import를 하드코딩하고 있습니다.

    import React, { Component } from 'react'
    import Component1 from './Component1'
    import Component2 from './Component2'
    import Component3 from './Component3'

    class Main extends Component {
        render() {
            var components = {
                'Component1': Component1,
                'Component2': Component2,
                'Component3': Component3
            };
            var type = 'Component1';  // just an example
            var MyComponent = Components[type];
            return <MyComponent />
        }
    }

    export default Main

하지만 저는 항상 컴포넌트를 변경/추가합니다.컴포넌트의 이름과 경로만 저장하고 이들을 다른 파일로 동적으로 Import하는 방법이 있습니까?

내가 달성하려고 했던 것에 대해 약간의 혼란이 있었을지도 모른다고 생각한다.문제가 해결되었고, 아래에 해결 방법을 나타내는 코드를 보여드렸습니다.

개별 파일(컴포넌트)Index.js):

    let Components = {};

    Components['Component1'] = require('./Component1').default;
    Components['Component2'] = require('./Component2').default;
    Components['Component3'] = require('./Component3').default;

    export default Components

메인 파일(Main.js):

    import React, { Component } from 'react';
    import Components from './ComponentIndex';

    class Main extends Component {
        render () {
            var type = 'Component1'; // example variable - will change from user input
            const ComponentToRender = Components[type];
            return <ComponentToRender/>
        }
    }

    export default Main

이 방법을 사용하면 Import가 한 파일에 있고 한 번에 한 줄만 변경하면 되기 때문에 컴포넌트를 빠르게 추가하거나 제거할 수 있습니다.

질문이 너무 오래됐기 때문에 정답은 아마 괜찮았을 거예요.그러나 현재 같은 문제가 있는 경우 필요한 컴포넌트만 로드하고 다른 컴포넌트는 모두 로드하지 않도록 동적 Import를 사용해야 합니다.

const component = React.lazy(() => import('./component.jsx'));

여기서 예를 시험해 보세요: 데모

import React, { Component } from 'react'
import Component1 from './Component1'
import Component2 from './Component2'
import Component3 from './Component3'

class Main extends Component {
    render() {
        var type = 'Component1';  // just an example
        return (
          <div>
            {type == "Component1" && <Component1 />}
            {type == "Component2" && <Component2 />}
            ...
          </div>
        )
    }
}

export default Main

설치된 조건부 렌더링을 사용할 수 있습니다.도움이 되었으면 좋겠다

체크해 주세요

다음은 또 다른 해결 방법입니다.필요한 컴포넌트 리스트가 표시됩니다.list = ['c1', 'c2', 'c3']. json 파일에서 배열로 풀 수 있습니다(redex-store를 사용하여 this.props.getForms()로 폼을 가져옵니다).단, 컴포넌트 목록을 수동으로 생성하여 액세스할 수 있습니다.

    componentDidMount = () => {
//we get elements list from any source to redux-store
        this.props.getForms();
//access redux-store to the list
        const forms = this.props.configBody.sets;
//make deep object copy
        const updatedState = { ...this.state };
        updatedState.modules = [];
        if (forms) {
//here is the very dynamic import magic: we map the import list and prepare to store the imports in Component`s state
            const importPromises = forms.map(p =>
                import(`../TemplateOrders/Template${p.order}`)
                    .then(module => {
                        updatedState.modules.push(module.default)
                    })
                    .catch(errorHandler(p))
            )
//wait till all imports are getting resolved
            Promise.all(importPromises)
                .then(res =>
//then run setState
                    this.setState({ ...updatedState }, () => {
                        console.log(this.state);
                    }))
        }
    }

    render() {
        const forms = this.props.configBody.sets;
//we iterate through the modules and React.createElemet`s 
        const list = this.state.modules
            ? this.state.modules.map((e, i) =>
                createElement(e, { key: forms[i].title }, null)
            )
            : [];
        return (
            <Fragment>
                <Link to='/'>Home</Link>
                <h1>hello there</h1>
//push them all to get rendered as Components
                {list.map(e => e)}
            </Fragment>
        )
    }

따라서 앱이 로드되면 필요한 모듈을 가져옵니다.

약속을 사용하여 Import하려고 했는데 모듈은 이미 약속입니다.

최근에 서버에서 아약스할 필요가 있는 경우에는 모듈을 분할한 후 require(또는 그와 비슷한 것)로 번들해야 합니다.

구성 요소를 마이크로 앱으로 번들하고 URL에서 애플리케이션에 핫 로드할 수 있습니다.사이트 레벨의 설정에 근거해 루트로부터의 컴포넌트 및 마이크로 앱의 동적 Import를 서포트하는 POC를 다음에 나타냅니다.

https://github.com/eschall/react-micro-frontend

약속 없이 동적 Import를 수행할 수 있는 또 하나의 방법:

import React from "react";
import ColumnSet1Brick from "./sets/column-set/column-set-1-brick";
import ColumnSet2Brick from "./sets/column-set/column-set-2-brick";
import ColumnSet3Brick from "./sets/column-set/column-set-3-brick";
import ColumnSet4Brick from "./sets/column-set/column-set-4-brick";

const setClasses = {
  ColumnSet1Brick,
  ColumnSet2Brick,
  ColumnSet3Brick,
  ColumnSet4Brick
};

export default class SetBrickStack extends React.Component {

  ...



  getColumnSetInstance = (n) => new (setClasses[`ColumnSet${n}Brick`])(this.paramFactory.getBasicProps());

  getBricksOnInit = () => {
    const columnSets = [1, 2, 3, 4];
    const bricksParams = columnSets.map(this.getColumnSetInstance);
    return bricksParams;
  };
}

비결은 babel이 클래스를 react__와 같은 다른 이름으로 컴파일하는 것입니다.WEBPACK_IPORTED_MODULE_1__기본값으로 접근하려면 컴파일 모듈 이름을 하나의 객체에 할당해야 합니다.그러므로 참조를 사용하여 객체를 컴파일하는 setClasses가 존재합니다.

const setClasses = {
  ColumnSet1Brick: react__WEBPACK_IMPORTED_MODULE_1___default,
  ColumnSet2Brick: react__WEBPACK_IMPORTED_MODULE_2___default,
  ColumnSet3Brick: react__WEBPACK_IMPORTED_MODULE_3___default,
  ColumnSet4Brick: react__WEBPACK_IMPORTED_MODULE_4___default
};

통상적인 클래스명으로 Import 할 수 있습니다.

new (setClasses[`ColumnSet${n}Brick`])(parameters)

React.createElement를 사용하는 컴포넌트 빌드 함수를 작성할 수 있습니다.이렇게 하면 도우미 파일에서 함수를 가져올 수 있습니다.이 예에서는 상세 정보가 없으면 더 많은 코드를 표시하기가 어렵지만 이 컴포넌트에서 논리를 완전히 삭제하는 것이 목적인 경우 이 파일에서 상태 도우미를 사용할 수도 있습니다.

class Main extends Component {

constructor(props) {
  super();
  this.state = { displayComponent: Component1 }
}

buildComponent = () => {
  // create element takes additional params for props and children
  return React.createElement( this.state.displayComponent )
}

render() {
    var type = 'Component1';  // just an example
    return (
      <div>
        { this.buildComponent() }
      </div>
    )
}

}

동적 Import를 사용해야 하는 경우 필요한 컴포넌트만 로드하고 다른 컴포넌트는 모두 로드하지 않도록 합니다.코드 검색 사용

(async () => {
  const { Component1 } = await import('./Component1');
})();

'react-router-dom'에서 Route 및 Switch를 사용하여 경로를 기반으로 구성 요소를 동적으로 렌더링할 수 있습니다.여기 샘플이 있습니다.

render() {
return (
  <>
    <Header  />
    <BrowserRouter>
      <Switch>
        <Route path="/abc" exact render={() => (<Abc />)}/>
        <Route path="/abcd" exact render={() => (<Abcd {...this.props} />)}/>
        <Route path="/xyz" exact render={() => (<Xyz />)}/>
        
      </Switch>
    </BrowserRouter>
    <Footer /></>
);  }

언급URL : https://stackoverflow.com/questions/48268507/react-dynamically-import-components

반응형