【问题标题】:React.createElement: type is invalid using react-bootstrap in ClojureScriptReact.createElement:类型在 ClojureScript 中使用 react-bootstrap 无效
【发布时间】:2022-05-12 13:50:05
【问题描述】:

我正在尝试在 re-frame 项目中使用 react-bootstrap。我已经安装了 react-bootstrap

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

【问题讨论】:

  • 我不知道closerscript,但是您是否在代码中缺少 Dropdown.Toggle 组件?你有一个可运行的 MWE,我可以在没有设置的情况下立即运行吗?
  • 对,我使用的是 DropdownToggle,只是忘记将其复制到代码示例中。您可以运行我发布的 MWE,方法是运行 npm install,然后运行 ​​npx shadow-cljs watch app,然后转到 localhost:8280

标签: react-bootstrap clojurescript reagent re-frame shadow-cljs


【解决方案1】:

该文档有一节介绍如何为 npm 包使用translate ES import

在那里你会发现["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 以使用该属性并获得您实际需要的内容。

【讨论】:

  • 不幸的是,使用这种$default 语法,我得到了另一个错误,这一次是针对任何 react-bootstrap 组件,而不仅仅是DropdownMenu:“警告:React.createElement:类型无效——需要一个字符串(对于内置组件)或类/函数(用于复合组件)但得到:未定义。”
  • 同样使用:refer 导入,像这样["react-bootstrap" :refer [Button Dropdown DropdownToggle DropdownMenu] 会产生相同的undefined 错误。 @Thomas 也许 react-bootstrap 使用了一些与 shadow-cljs 不兼容的奇怪文件布局?
  • 用更多细节扩展了我的答案。该包裹确实似乎有问题,导致了一个奇怪的案例。
  • 这很有帮助,非常感谢托马斯!
猜你喜欢
  • 2019-08-19
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
  • 2017-12-22
  • 1970-01-01
  • 2018-12-25
  • 2017-07-17
  • 1970-01-01
相关资源
最近更新 更多