繁体   English   中英

React 传播运算符 (...props) 没有按预期工作?

[英]React spread operator (...props) not working as expected?

我正在尝试使用传播运算符( https://reactjs.org/docs/jsx-in-depth.html#spread-attributes )将 GeolocationCoordinates 对象传递给子组件,但由于某种原因在子道具中它只是空对象:

interface HUDState {
    geoCoords: GeolocationCoordinates | null
    login: boolean
}

function MainHUD(props: HUDState) {
    console.log('MainHUD props:', props)
   
    return (
        <Background>
            {
             props.geoCoords !== null && props.geoCoords !== undefined ? 
                 <Map {...props.geoCoords} /> 
            : 
              null
            }
        </Background>
    )
}

function Map(props: GeolocationCoordinates) {
    console.log('Map props:', props)

        return (
            <MapContainer style={MapContainerStyle} center={[props.latitude, props.longitude]} zoom={13} scrollWheelZoom={false}>
                <TileLayer
                    attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                    url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                />
            </MapContainer>
        )
}

控制台(地图子道具为空):

MainHUD props: Object { login: false, geoCoords: GeolocationCoordinates }
Map props: Object {  } <-- Why is this empty here?

但是,如果在定义子地图标记时在父组件中手动指定道具,一切正常(实际上我收到警告 Map is missing properties 因为我只想要纬度和经度):

<Map latitude={props.geoCoords.latitude} longitude={props.geoCoords.longitude} />

控制台(现在定义了地图子道具):

Map props: Object { latitude: 40.2927067, longitude: -73.9837427 } <-- Not empty now!

我正在使用 webpack/babel 将我的 tsx 转译回 javascript,它没有抛出任何错误。 我已经包含了"@babel/plugin-transform-spread" ,尽管这篇文章( https://babeljs.io/docs/en/babel-plugin-transform-spread )说它应该包含在"@babel/env"预设。 我也将插件添加到 webpack.config.js 和 .babelrc 中,因为我不确定哪个需要它。

webpack.config.js:

const path = require('path');

module.exports = {
    entry: path.resolve(__dirname, './src/App.tsx'),
    module: {
        rules: [
            {
                test: /\.(ts|js)x?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: "babel-loader",
                        options: {
                            presets: [
                                "@babel/env",
                                "@babel/react",
                                "@babel/typescript"
                            ],
                            plugins: [
                                ["@babel/plugin-transform-spread", {
                                    "loose": true
                                }]
                            ]
                        },
                    }
                ]
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
        ]
    },
    resolve: {
        extensions: ['*', '.json', '.js', '.jsx', '.ts', '.tsx']
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'app.bundle.js',
    },
    devServer: {
        static: {
            directory: path.join(__dirname, './dist'),
        },
        server: {
            type: 'https',
            options: {
                key: './example.com+4-key.pem',
                cert: './example.com+4.pem',
            }
        }
    }
}

.babelrc:

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react",
        "@babel/preset-typescript"
    ],
    "plugins": [
        [
            "@babel/plugin-transform-spread",
            {
                "loose": true
            }
        ]
    ]
}

包.json:

{
  "name": "example.com",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/react": "^18.0.26",
    "@types/react-dom": "^18.0.9",
    "@types/styled-components": "^5.1.26",
    "leaflet": "^1.9.3",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.40.0",
    "react-leaflet": "^4.2.0",
    "styled-components": "^5.3.6"
  },
  "devDependencies": {
    "@babel/core": "^7.20.5",
    "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
    "@babel/plugin-transform-spread": "^7.19.0",
    "@babel/preset-env": "^7.20.2",
    "@babel/preset-react": "^7.18.6",
    "@babel/preset-typescript": "^7.18.6",
    "babel-loader": "^9.1.0",
    "css-loader": "^6.7.2",
    "style-loader": "^3.3.1",
    "typescript": "^4.9.4",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  }
}

我已经吃饱了,我补充说

props.geoCoords !== null && props.geoCoords !== undefined

在渲染子 Map 组件之前,它仍然什么都不做。 我也理解传播运算符意味着像数组这样的可迭代对象,但是在 React 和我上面链接的 React 示例中,它用于 props 对象。 这就是为什么我在配置中添加了 loose 选项,但它仍然无济于事。 我是否从根本上误解了有关如何使用此运算符的某些内容? 我的设置有问题吗?

我在这个问题上搜索了很多,大多数人似乎试图在 React 之外的对象上使用运算符,或者首先在转换运算符时遇到问题,这不是我的问题。 我知道这是可选的,我可以在没有这个功能的情况下构建我的应用程序的其余部分,但我预见到我的组件会变得更加复杂并且能够只传递整个道具对象而无需手动指定每个字段将是一个很大的帮助。 非常感谢任何可以帮助我的人。

布尔上下文中遇到空对象时被认为是true 看看这里: Truthy

const geoCoords = {};

console.log(geoCoords !== null && geoCoords !== undefined); // true

因此,如果geoCoords是一个空对象 ( {} ), <Map {...props.geoCoords} />仍将被渲染,但不会传递任何道具。

确保geoCoords不是空对象,您可以执行以下操作:

<Background>
  {props.geoCoords && <Map {...props.geoCoords} />}
</Background>

或者也检查是否是一个空对象:

<Background>
    {props.geoCoords && Object.keys(props.geoCoords).length > 0 && (
      <Map {...props.geoCoords} />
    )}
</Background>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM