React-leaflet 自定义组件 - 未传递上下文?

React-leaflet custom component - context not being passed?

我正在为 react-leaflet 编写自定义组件。它是一个可编辑的弹出窗口,具有一些其他功能。 Here is a codesandbox for an example.. The source code for the component is here。这个例子只是做了一个import EditablePopup from 'my-react-leaflet-popup-plugin',这是我项目中的一个.js文件。效果不错。

我正在尝试使用 webpack 将其打包为节点模块,以便其他人可以使用它。它编译没有问题。你可以看到我的webpack.config.jshere。然后我使用 npm link 到 link 这个模块到我本地机器上的测试项目中。当我这样做时,我收到错误消息:

TypeError: Cannot read property 'leafletElement' of null

  460 |   value: function value() {
  461 |     var e = this;
  462 |     this.props.open && setTimeout(function () {
> 463 |       e.thePopup.leafletElement._source.openPopup();
      | ^  464 |     }, .001);
  465 |   }
  466 | }, {

即使我去掉那个子句,我也会得到这个:

TypeError: Cannot read property 'openPopup' of undefined


  9226 | // @method openOn(map: Map): this
  9227 | // Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
  9228 | openOn: function openOn(map) {
> 9229 |   map.openPopup(this);
       | ^  9230 |   return this;
  9231 | },
  9232 | onAdd: function onAdd(map) {

它就像弹出窗口试图将自己添加到地图中,但没有找到父地图组件的地图实例。我的直觉是,出于某种原因,当使用 webpack 构建它并将其作为 npm 模块导入时,react-leaflet 映射的上下文没有正确传递到我的组件。我不太明白,因为我的组件只是 react-leaflet 的 <Popup> 组件的修饰版。我的 <EditablePopup> 使用 <Popup> 作为直接子代,它本质上应该接收 LeafletConsumer 上下文消费者包装器。

我不确定为什么这个组件在我的项目中 link 运行良好,但在通过 webpack 构建并通过 npm 导入时出现此错误。

我发布的答案受到 in 的启发。我的问题似乎至少与 React Context API not working from custom NPM component library 这个问题有些相关 ,那些人仍在寻找答案 - 也许这会有所帮助。

我不得不在 webpack.config.jspackage.json 中进行调整以解决此问题。


webpack.config.js

改变这个:

  libraryTarget: 'commonjs2'

对此:


      library: "EditablePopup",
      libraryTarget: 'umd'

以及将 mode: development 添加到 module.exports


package.json

将我的一些 dependencies 移动到 peerDependencies:


    // Change from this:
      "dependencies": {
        "html-react-parser": "^0.10.0",
        "leaflet": "^1.6.0",
        "react": "^16.12.0",
        "react-contenteditable": "^3.3.3",
        "react-dom": "^16.12.0",
        "react-leaflet": "^2.6.1",
        "webpack": "^4.41.5"
      },
      "peerDependencies": {
        "react": "^16.12.0",
        "react-dom": "^16.12.0",
        "react-leaflet": "^2.6.1",
        "leaflet": "^1.6.0"
      }

    // to this:
      "dependencies": {
        "html-react-parser": "^0.10.0",
        "react-contenteditable": "^3.3.3",
        "webpack": "^4.41.5"
      },
      "peerDependencies": {
        "react": "^16.12.0",
        "react-dom": "^16.12.0",
        "react-leaflet": "^2.6.1",
        "leaflet": "^1.6.0"
      }


我很确定 webpack.config.js 的变化才是最重要的。为了完整起见,以下是对该文件的更改:


    // webpack.config.js

    var path = require('path');
    module.exports = {
        entry: './src/EditablePopup.js',
        output: {
            path: path.resolve(__dirname, 'build'),
            filename: 'EditablePopup.js',
    -       libraryTarget: 'commonjs2',
    +       library: "EditablePopup",
    +       libraryTarget: 'umd'
        },
    +   mode: "development",
        module: {
            rules: [
                {
                    test: /\.js$/,
                    include: path.resolve(__dirname, 'src'),
                    exclude: /(node_modules|bower_components|build)/,
                    use: [
                        {
                            loader: 'babel-loader',
                            options: {
                                presets: ['@babel/preset-env']
                            }
                        }
                    ]
                },
                { 
                    test : /\.css$/, 
                    use: [
                        { loader: 'style-loader' },
                        { loader: 'css-loader' }
                    ]  
                }
            ]
        },
        externals: {
            'react-dom': 'commonjs react-dom',
            leaflet: {
                commonjs: 'leaflet',
                commonjs2: 'leaflet',
                root: 'L'
            },
            'react-leaflet': {
                commonjs: 'react-leaflet',
                commonjs2: 'react-leaflet',
                root: 'ReactLeaflet'
            },
            react: {
                commonjs: 'react',
                commonjs2: 'react',
                root: 'React'
            }
        }
    };

我在工作场所遇到了类似的问题,我现在怀疑我们声明 webpack 配置的(类似)方式是罪魁祸首。但对我来说,仅仅改变 libraryTarget 没有任何效果。在描述我们的设置后,我的见解如下...

我们有一组可视化组件,我们正在将其捆绑到 "library" 中,然后导入到主项目中。主项目需要获取一些外部数据,但需要在整个库组件的任意位置使用。而且我们不想到处传递道具。那么上下文,对吗?除非提供者(我们在 "main" 项目中设置和初始化)和消费者位于库边界的不同侧,否则消费者的上下文总是未定义的(或者更确切地说,无论 [ 的默认值是什么) =24=] ...我们没有使用初始化器)。

总之,快进一堆。如果我从将库中的每个不同组件列为自己独立的 "entry"(在 webpack 文件中)改为构建一个 index.js 文件来导入和重新导出所有内容——并且只包含那个文件文件作为单数 "entry"(在 webpack 中)——然后事情开始起作用了。

因为 React context API 需要共享创建的 Context 对象,但共享的概念(无论如何我猜)是在模块级别。它不能 真正 全局。所以不同的入口点,不同的模块,不同的上下文对象。消费者被冷落。

也许您需要将自定义组件包装在 withLeaflet 中?我发现 在使用 react-leaflet.

创建自定义组件的步骤中非常清楚

使用 HOC 将使地图(以及上下文的其余部分)在地图安装后可用于 createLeafletElement 的实现。