>  기사  >  웹 프론트엔드  >  React 및 Redux의 동적 가져오기(코드 포함)

React 및 Redux의 동적 가져오기(코드 포함)

不言
不言앞으로
2019-03-23 09:51:132525검색

이 기사의 내용은 React 및 Redux(코드 포함)의 동적 가져오기에 대한 내용이며, 필요한 친구들이 참고할 수 있기를 바랍니다.

코드 분리 및 동적 가져오기

대규모 웹 애플리케이션의 경우 코드 구성이 매우 중요합니다. 고성능이면서도 이해하기 쉬운 코드를 작성하는 데 도움이 됩니다. 가장 간단한 전략 중 하나는 코드 분리입니다. Webpack과 같은 도구를 사용하면 코드를 더 작은 부분으로 분할할 수 있으며, 이는 정적 및 동적의 두 가지 전략으로 구분됩니다.

정적 코드 분리를 사용하면 애플리케이션의 각 부분을 지정된 진입점으로 처리하는 것부터 시작합니다. 이를 통해 Webpack은 빌드 시 각 진입점을 별도의 번들로 분할할 수 있습니다. 앱의 어느 부분이 가장 많이 조회될지 알면 완벽합니다.

동적 가져오기는 Webpack의 가져오기 방법을 사용하여 코드를 로드합니다. 가져오기 메서드는 약속을 반환하므로 비동기 대기를 사용하여 반환 결과를 처리할 수 있습니다.

// getComponent.js
async function getComponent() {
   const {default: module} = await import('../some-other-file')
   const element = document.createElement('p')
   element.innerHTML = module.render()
   return element
}

매우 부자연스러운 예이지만 이 방법이 얼마나 간단한지 알 수 있습니다. Webpack을 사용하여 무거운 작업을 수행함으로써 애플리케이션을 여러 모듈로 나눌 수 있습니다. 우리에게 필요한 코드는 사용자가 애플리케이션의 특정 부분을 클릭할 때만 로드됩니다.

이 접근 방식을 React가 제공하는 제어 구조와 결합하면 지연 로딩을 통해 코드 분할을 수행할 수 있습니다. 이를 통해 마지막 순간까지 코드 로드를 지연시켜 초기 페이지 로드를 줄일 수 있습니다.

React로 지연 로딩 처리

모듈을 가져오려면 어떤 API를 사용해야 할지 결정해야 합니다. 콘텐츠를 렌더링하기 위해 React를 사용하고 있다는 점을 고려하여 거기서부터 시작해 보겠습니다.

다음은 뷰 네임스페이스를 사용하여 모듈 구성 요소를 내보내는 간단한 API입니다.

// my-module.js
import * as React from 'react'

export default {
    view: () => <p>My Modules View</p>
}

이제 import 메서드를 사용하여 이 파일을 로드하므로

async function getComponent() {
    const {default} = await import('./my-module')
    return React.createElement(default.view)
})

와 같은 모듈의 뷰 구성 요소에 쉽게 액세스할 수 있습니다. 하지만 여전히 React에서는 모듈을 지연 로드하기 위해 이 메서드를 사용하지 않습니다. LazyLoadModule 구성요소를 생성하면 됩니다. 이 구성 요소는 특정 모듈에 대한 보기 구성 요소를 구문 분석하고 렌더링하는 역할을 합니다.

// lazyModule.js
import * as React from "react";

export class LazyLoadModule extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      module: null
    };
  }
 
  // after the initial render, wait for module to load
  async componentDidMount() {
    const { resolve } = this.props;
    const { default: module } = await resolve();
    this.setState({ module });
  }

  render() {
    const { module } = this.state;

    if (!module) return <p>Loading module...</p>;
    if (module.view) return React.createElement(module.view);

  }
}

다음은 LazyLoadModule 컴포넌트를 사용하여 모듈을 로드하는 모습입니다.

// my-app.js

import {LazyLoadModule} from './LazyLoadModule'

const MyApp = () => (
    <p className=&#39;App&#39;>
        <h1>Hello</h1>
        <LazyLoadModule resolve={() => import('./modules/my-module')} />
    </p>
)

ReactDOM.render(<MyApp />, document.getElementById('root'))

다음은 몇 가지 예외 처리를 추가한 온라인 예시입니다.

https://codesandbox.io/embed/…

React를 사용하여 각 모듈의 로딩을 처리하면 애플리케이션에서 언제든지 구성요소를 지연 로드할 수 있습니다. 여기에는 중첩된 모듈도 포함됩니다.

Redux 사용

지금까지 애플리케이션 모듈을 동적으로 로드하는 방법을 살펴보았습니다. 그러나 로드 시 모듈에 올바른 데이터를 입력해야 합니다.

redux 스토어를 모듈에 연결하는 방법을 살펴보겠습니다. 각 모듈의 뷰 구성 요소를 노출하여 각 모듈에 대한 API를 만들었습니다. 각 모듈에 대해 리듀서를 노출하여 이를 확장할 수 있습니다. 또한 애플리케이션 저장소에 모듈 상태가 존재할 이름을 노출해야 합니다.

// my-module.js
import * as React from 'react'
import {connect} from 'react-redux'

const mapStateToProps = (state) => ({
    foo: state['my-module'].foo,
})
const view = connect(mapStateToProps)(({foo}) => <p>{foo}</p>)

const fooReducer = (state = 'Some Stuff') => {
    return state
}
const reducers = {
    'foo': fooReducer,
}

export default {
    name: 'my-module',
    view,
    reducers,
}

위의 예는 모듈이 렌더링하는 데 필요한 상태를 얻는 방법을 보여줍니다.

하지만 먼저 스토어에서 더 많은 작업을 해야 합니다. 모듈이 로드될 때 모듈의 reducer를 등록할 수 있어야 합니다. 따라서 모듈 dispatcheaction을 수행하면 store가 업데이트됩니다. 이를 달성하기 위해 replacementReducer 메소드를 사용할 수 있습니다. dispatche 一个 action 时,我们的 store 就会更新。我们可以使用 replaceReducer 方法来实现这一点。

首先,我们需要添加两个额外的方法,registerDynamicModuleunregisterDynamicModule 到我们的 store 中。

// store.js
import * as redux form 'redux'

const { createStore,  combineReducers } = redux

// export our createStore function
export default reducerMap => {
    
    const injectAsyncReducers = (store, name, reducers) => {
        // add our new reducers under the name we provide
        store.asyncReducers[name] = combineReducers(reducers);
        // replace all of the reducers in the store, including our new ones
        store.replaceReducer(
            combineReducers({
                ...reducerMap,
                ...store.asyncReducers
            })
        );
    };
    
    // create the initial store using the initial reducers that passed in
    const store = createStore(combineReducers(reducerMap));
    // create a namespace that will later be filled with new reducers
    store.asyncReducers = {};
    // add the method that will allow us to add new reducers under a given namespace
    store.registerDynamicModule = ({ name, reducers }) => {
        console.info(`Registering module reducers for ${name}`);
        injectAsyncReducers(store, name, reducers);
    };
    // add a method to unhook our reducers. This stops our reducer state from updating any more.
    store.unRegisterDynamicModule = name => {
        console.info(`Unregistering module reducers for ${name}`);
        const noopReducer = (state = {}) => state;
        injectAsyncReducers(store, name, noopReducer);
    };
    
    // return our augmented store object
    return store;
}

如你所见,代码本身非常简单。 我们将两种新方法添加到我们的 store 中。 然后,这些方法中的每一种都完全取代了我们 store 中的 reducer

以下是如何创建扩充 store

import createStore from './store'

const rootReducer = {
    foo: fooReducer
}

const store = createStore(rootReducer)

const App = () => (
    <Provider store={store}>
        ...
    </Provider>
)

接下来,需要更新 LazyLoadModule ,以便它可以在我们的 store 中注册 reducer 模块。

我们可以通过 props 获取 store。这很简单,但这意味着我们每次都必须检索我们的 store먼저 스토어에 registerDynamicModuleunregisterDynamicModule

이라는 두 가지 메소드를 추가해야 합니다.

// lazyModule.js 
export class LazyLoadModule extends React.component {
    ...
    async componentDidMount() {
        ...
        const {store} = this.context
    }
}

LazyLoadModule.contextTypes = {
    store: PropTypes.object,
}
보시다시피 코드 자체는 매우 간단합니다. store에 두 가지 새로운 메소드를 추가했습니다. 그러면 이러한 각 방법은 storereducer를 완전히 대체합니다. 확장 store를 생성하는 방법은 다음과 같습니다.
// my-module.js
export default {
    name: 'my-module',
    view,
    reducers,
}
다음으로 🎜LazyLoadModule🎜을 업데이트하여 🎜store🎜에 🎜reducer🎜 모듈을 등록할 수 있도록 해야 합니다. 🎜🎜props를 통해 store를 얻을 수 있습니다. 이는 간단하지만 매번 store를 검색해야 하므로 버그가 발생할 수 있습니다. 이를 염두에 두고 🎜LazyLoadModule🎜 구성 요소가 🎜store🎜을 가져오도록 하세요. 🎜🎜 🎜react-redux 🎜 구성 요소가 🎜store🎜를 컨텍스트에 추가하면 🎜contextTypes🎜를 사용하여 🎜LazyLoadModule🎜에서 가져옵니다. 🎜
// lazyModule.js 
export class LazyLoadModule extends React.component {
    ...
    async componentDidMount() {
        ...
        const {store} = this.context
    }
}

LazyLoadModule.contextTypes = {
    store: PropTypes.object,
}

现在可以从 LazyLoadModule 的任何实例访问我们的 store。 剩下的唯一部分就是把 reducer 注册到 store 中。 记住,我们是这样导出每个模块:

// my-module.js
export default {
    name: 'my-module',
    view,
    reducers,
}

更新 LazyLoadModulecomponentDidMountcomponentWillUnmount 方法来注册和注销每个模块:

// lazyModule.js 
export class LazyLoadModule extends React.component {
    ...
    async componentDidMount() {
        ...
        const { resolve } = this.props;
        const { default: module } = await resolve();
        const { name, reducers } = module;
        const { store } = this.context;
        if (name && store && reducers)
            store.registerDynamicModule({ name, reducers });
         this.setState({ module });
    }
    ...
    
    componentWillUnmount() {
        const { module } = this.state;
        const { store } = this.context;
        const { name } = module;
        if (store && name) store.unRegisterDynamicModule(name);
    }
}

线上示例如下:
https://codesandbox.io/s/znx1...

总结:

通过使用 Webpack 的动态导入,我们可以将代码分离添加到我们的应用程序中。这意味着我们的应用程序的每个部分都可以注册自己的 components 和 reducers,这些 components 和 reducers将按需加载。此外,我们还减少了包的大小和加载时间,这意味着每个模块都可以看作是一个单独的应用程序。

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

위 내용은 React 및 Redux의 동적 가져오기(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제