gloriasoft / veaury

Use React in Vue3 and Vue3 in React, And as perfect as possible!
MIT License
1.31k stars 83 forks source link

[React In Vue] 关于组合组件的使用问题 #118

Closed baijunjie closed 6 months ago

baijunjie commented 6 months ago

感谢百忙之中查看,我又遇到了一些使用问题 😂

有一些复杂的交互组件,需要几个组件组合使用,例如 Dropdown

<script setup>
import { applyPureReactInVue } from "veaury";
import {
  Dropdown,
  DropdownTrigger,
  DropdownMenu,
  DropdownItem,
  Button,
} from "@nextui-org/react";

const ReactDropdown = applyPureReactInVue(Dropdown);
const ReactDropdownTrigger = applyPureReactInVue(DropdownTrigger);
const ReactDropdownMenu = applyPureReactInVue(DropdownMenu);
const ReactDropdownItem = applyPureReactInVue(DropdownItem);
const ReactButton = applyPureReactInVue(Button);
</script>

<template>
  <ReactDropdown>
    <ReactDropdownTrigger>
      <ReactButton>Trigger</ReactButton>
    </ReactDropdownTrigger>
    <ReactDropdownMenu>
      <ReactDropdownItem>Item1</ReactDropdownItem>
      <ReactDropdownItem>Item2</ReactDropdownItem>
    </ReactDropdownMenu>
  </ReactDropdown>
</template>

这时,工作一切正常,我点击 Trigger 按钮,就会出现 Dropdown 下拉菜单

但是由于组件封装的需要,不同功能组件需要拆分到其他文件中去,因此我将 ReactButton 作为一个独立组件创建了一个 ReactButton.vue 的文件

<script setup>
import { applyPureReactInVue } from "veaury";
import { Button } from "@nextui-org/react";

const ReactButton = applyPureReactInVue(Button);
</script>

<template>
  <ReactButton>
    <slot />
  </ReactButton>
</template>

然后将 ReactButton 从外部导入

<script setup>
import { applyPureReactInVue } from "veaury";
import {
  Dropdown,
  DropdownTrigger,
  DropdownMenu,
  DropdownItem,
} from "@nextui-org/react";

const ReactDropdown = applyPureReactInVue(Dropdown);
const ReactDropdownTrigger = applyPureReactInVue(DropdownTrigger);
const ReactDropdownMenu = applyPureReactInVue(DropdownMenu);
const ReactDropdownItem = applyPureReactInVue(DropdownItem);

import ReactButton from "./components/ReactButton.vue";
</script>
<template>
  <ReactDropdown>
    <ReactDropdownTrigger>
      <ReactButton>Trigger</ReactButton>
    </ReactDropdownTrigger>
    <ReactDropdownMenu>
      <ReactDropdownItem>Item1</ReactDropdownItem>
      <ReactDropdownItem>Item2</ReactDropdownItem>
    </ReactDropdownMenu>
  </ReactDropdown>
</template>

此时就出现了问题,Dropdown 失效了,我点击按钮,没有任何反应。😓

于是我看了一下两种方式生成的 html 结构 能够正常工作的结构

image

不能够征程工作的结构

image

也就是说,当我将一个转换过的 React 组件封装成单文件组件后,veaury 会额外再添加两层 div, 分别是 data-use-vue-component-wrap__use_react_component_wrap

以下链接是重现的最小Demo https://codesandbox.io/p/devbox/vue3-veaury-nextui-org-react-3r7tsw?file=%2Fsrc%2FApp.vue%3A6%2C16

我不太明白 veaury 其中的原理,并且我也不太清楚此类 React 组件的实现原理,为什么多了两层 div,就会导致这些组件的组合性失效。不知道大神有何建议?不胜感激🙏🏻

devilwjp commented 6 months ago

@baijunjie 你第一个例子,所有的组件都是applyPureReactInVue就是确保React组件内部的React组件,呈现react原始态作为children传入,所以不会有包囊层。 而你第二个例子,你把一个react组件输出成了一个标准的SFC Vue组件了,已经不再是一个react组件了,其实就是变成了applyReactInVue了,不再是pure

你的这个issue正好说明了applyReactInVue和applyPureReactInVue的区别

devilwjp commented 6 months ago

@baijunjie 建议你不要用.vue文件,直接用.js或者jsx文件导出 因为.vue文件的导出,vue在编译时会再包装一个下,导致veaury转换的组件无法再获取到react原始态了,也就是veaury已经不知道这个组件是veaury转换过来的组件了,因为你自己外面又包装过了。所以veaury只能降级使用applyReactInVue去处理了。

你将ReactButon.vue改成ReactButton.js,不要做包装,正常的导出就好。

import { applyPureReactInVue } from "veaury";
import { Button } from "@nextui-org/react";

export default applyPureReactInVue(Button);
baijunjie commented 6 months ago

原来如此,感谢🙏🏻