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.js
和 package.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
的实现。
我正在为 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 导入时出现此错误。
我发布的答案受到
我不得不在 webpack.config.js
和 package.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
的实现。