React.createElement: 在 ClojureScript 中使用 react-bootstrap 类型无效

React.createElement: type is invalid using react-bootstrap in ClojureScript

我正在尝试在重新构建项目中使用 react-bootstrap。我已经安装了 react-bootstrap with

npm install react-bootstrap

并像下面这样使用它的组件:

  (:require
   ;; ...
   ["react-bootstrap/Button" :as Button]
   ;; ...

(defn main-panel []
  [:div
   [:> Button "Hit me"]
  ]])

一切正常,直到我尝试制作下拉菜单,更准确地说,直到我尝试使用 DropdownMenu。我把它插入the example之后的打嗝的那一刻

[:> Dropdown
  [:> DropdownToggle "button"]
  [:> DropdownMenu {:variant :dark}
    [:> DropdownItem "action1"]
    [:> DropdownItem "action2"]
    [:> DropdownItem "action3"]]]

我在浏览器控制台中得到以下信息:

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.

我对整个前端世界都非常陌生,所以我不确定是我做错了什么,还是 react-bootstrap、试剂或任何其他部分存在错误的项目。 这是这个问题的 MWE:https://github.com/lockie/react-bootstrap-cljs-demo

文档中有一节介绍如何 translate ES import npm 包。

在那里你会发现 ["react-bootstrap/Button" :as Button] 应该是 ["react-bootstrap/Button$default" :as Button] 而不是(翻译 import Button from "react-bootstrap/Button";

但这仅在使用实际 ESM 代码时适用。然而,react-bootstrap 包是一个包含 ESM 和 CommonJS 的混合包。 shadow-cljs 在这种情况下默认情况下不会使用 ESM。

因此,一种选择是 shadow-cljs 使用 ESM 代码,方法是将其包含在构建配置中。

:js-options {:entry-keys ["module" "browser" "main"]}

这将需要为每个需求使用 $default,因为它们都是默认导出。

另一种选择是使用默认的 CommonJS 代码。然而,这似乎打包不一致,这意味着大多数都能正常工作,但有一个例外。如果我将您的示例代码更改为

,它就可以正常工作
(ns react-bootstrap-cljs-demo.views
  (:require
    [re-frame.core :as re-frame]
    [react-bootstrap-cljs-demo.subs :as subs]
    ["react-bootstrap/Button" :as Button]
    ["react-bootstrap/Dropdown" :as Dropdown]
    ["react-bootstrap/DropdownItem" :as DropdownItem]
    ["react-bootstrap/DropdownMenu$default" :as DropdownMenu]
    ["react-bootstrap/DropdownToggle" :as DropdownToggle]
    ))

因此,只有 DropdownMenu 以需要 $default 的方式包含在内。似乎 react-bootstrap 方面可能存在疏忽或错误。 shadow-cljs 只是跟随磁盘上的内容。

选择哪种方法由您决定。使用 ESM 可能会导致其他软件包出现问题,或者可能工作得很好。一切都取决于您实际发布的包。

如何解决这个问题?

作为一个小指南:我通过记录所需的 :as 别名并在浏览器控制台中查看它来解决这个问题。

就这样

(ns react-bootstrap-cljs-demo.views
  (:require
    [re-frame.core :as re-frame]
    [react-bootstrap-cljs-demo.subs :as subs]
    ["react-bootstrap/Button" :as Button]
    ["react-bootstrap/Dropdown" :as Dropdown]
    ["react-bootstrap/DropdownItem" :as DropdownItem]
    ["react-bootstrap/DropdownMenu$default" :as DropdownMenu]
    ["react-bootstrap/DropdownToggle" :as DropdownToggle]
    ))

(js/console.log "Button" Button)
(js/console.log "Dropdown" Dropdown)
(js/console.log "DropdownItem" DropdownItem)
(js/console.log "DropdownMenu" DropdownMenu)
(js/console.log "DropdownToggle" DropdownToggle)

如果从 DropdownMenu 中删除 $default,您会注意到日志行看起来与所有其他行不同,并且它是一个带有 default 属性.因此,您添加 $default 以使用 属性 并获得您实际需要的内容。