Rumah > hujung hadapan web > tutorial js > React和Redux的动态导入(附代码)

React和Redux的动态导入(附代码)

不言
Lepaskan: 2019-03-23 09:51:13
ke hadapan
2613 orang telah melayarinya

本篇文章给大家带来的内容是关于React和Redux的动态导入(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

代码分离与动态导入

对于大型 Web应用程序,代码组织非常重要。 它有助于创建高性能且易于理解的代码。 最简单的策略之一就是代码分离。 使用像 Webpack 这样的工具,可以将代码拆分成更小的部分,它们分为两个不同的策略,静态和动态。

通过静态代码分离,首先将应用程序的每个不同部分作为给定的入口点。 这允许 Webpack 在构建时将每个入口点拆分为单独的包。 如果我们知道我们的应用程序的哪些部分将被浏览最多,这是完美的。

动态导入使用的是 Webpack 的 import 方法来加载代码。由于 import 方法返回一个 promise,所以可以使用async wait 来处理返回结果。

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

虽然这是一个很不自然的例子,但是可以看到这是一个多么简单的方法。通过使用 Webpack 来完成繁重的工作,我们可以将应用程序分成不同的模块。当用户点击应用程序的特定部分时,才加载我们需要的代码。

如果我们将这种方法与 React 提供给我们的控制结构相结合,我们就可以通过延迟加载来进行代码分割。这允许我们将代码的加载延迟到最后一分钟,从而减少初始页面加载。

使用 React 处理延迟加载

为了导入我们的模块,我们需要决定应该使用什么 API。考虑到我们使用 React 来渲染内容,让我们从这里开始。

下面是一个使用 view 命名空间导出模块组件的简单API。

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

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

现在我们使用导入方法来加载这个文件,我们可以很容易地访问模块的 view  组件,例如

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

然而,我们仍然没有使用 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);

  }
}
Salin selepas log masuk

以下是使用 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'))
Salin selepas log masuk

下面是一个线上的示例,其中补充一些异常的处理。

https://codesandbox.io/embed/...

通过使用 React 来处理每个模块的加载,我们可以在应用程序的任何时间延迟加载组件,这包括嵌套模块。

使用 Redux

到目前为止,我们已经演示了如何动态加载应用程序的模块。然而,我们仍然需要在加载时将正确的数据输入到我们的模块中。

让我们来看看如何将 redux 存储连接到模块。 我们已经通过公开每个模块的视图组件为每个模块创建了一个 API。 我们可以通过暴露每个模块的 reducer 来扩展它。 还需要公开一个名称,在该名称下我们的模块状态将存在于应用程序的store 中。

// 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,
}
Salin selepas log masuk

上面的例子演示了我们的模块如何获得它需要渲染的状态。

但是我们需要先对我们的 store  做更多的工作。我们需要能够在模块加载时注册模块的 reducer。因此,当我们的模块 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;
}
Salin selepas log masuk

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

以下是如何创建扩充 store

import createStore from './store'

const rootReducer = {
    foo: fooReducer
}

const store = createStore(rootReducer)

const App = () => (
    <Provider store={store}>
        ...
    </Provider>
)
Salin selepas log masuk

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

我们可以通过 props 获取 store。这很简单,但这意味着我们每次都必须检索我们的 store,这可能会导致 bug。记住这一点,让 LazyLoadModule 组件为我们获取 store

react-redux 组件将 store 添加到上下文中时,只需要使用 contextTypesLazyLoadModule 中获取它。

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

LazyLoadModule.contextTypes = {
    store: PropTypes.object,
}
Salin selepas log masuk

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

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

更新 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);
    }
}
Salin selepas log masuk

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

总结:

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

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

Atas ialah kandungan terperinci React和Redux的动态导入(附代码). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Isu terkini
Mengapakah React.js begitu sukar untuk dipelajari?
daripada 1970-01-01 08:00:00
0
0
0
React.js / PHP / API
daripada 1970-01-01 08:00:00
0
0
0
Lebar tetingkap CSS React.js
daripada 1970-01-01 08:00:00
0
0
0
Menggunakan @ untuk import dalam React.js
daripada 1970-01-01 08:00:00
0
0
0
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan