【发布时间】:2020-09-14 21:43:55
【问题描述】:
这有点难以解释,但这里是:
我创建了 2 个 npm 包,它们在非 React rails 项目中导入和呈现。我最近做了一些修改,以允许在另一个更现代的 react 项目中使用它,他们正在使用 react 16 和钩子。
第一个包,我们称之为 ComponentA,可以单独使用,也可以嵌套在第二个包中,我们称之为 ComponentB。 ComponentA 和 ComponentB 都是在 react 15.x 中创建的,并且是类而不是使用钩子。
经过一番努力并试图不必更改任何子组件后,我们让这两个包都使用 Context 和 Providers 工作。 ComponentA 独立工作,而 ComponentB 与嵌套在其中的 ComponentA 独立工作。
编辑:
所以经过一些调试后,我认为我有一个理论。它看起来可能是反应的多个版本。我为 ComponentA 和 ComponentB 设置了 webpack 以使用 peerDependencies 并依赖它的父级反应。 (或者至少我认为我做到了)但是我在项目之间遇到了相互矛盾的故事。
当在开发中运行 ComponentB 并在其中嵌套 ComponentA 时,我将 window.React# = React 添加到两者中,然后在 js 控制台中检查了 React1 === React2 并得到了正确的结果。
当 npm linking ComponentB 进入我的 Rails 应用程序时,我在其中添加了另一个 window.React#,现在所有不同的反应变量都不相等。这也发生在我发布 ComponentA 和 B 并在我的 Rails 应用程序中使用发布的版本时。我彻底糊涂了。
结束编辑
组件A
设置上下文/提供者
import React from "react"
ComponentAContext = React.createContext({})
export class ComponentAProvider extends React.Component
constructor: (props) ->
super(props)
this.state = {...}
get_context: ->
Object.assign({ ... }, this.state, this.props)
render: ->
ctx = this.get_context()
<ComponentAContext.Provider value={ctx}>
{this.props.children}
</ComponentA.Provider>
export default ComponentAContext
组件实际使用Context和Provider
import { useContext, useEffect, useRef } from "react"
import ReactDOM from 'react-dom'
import ComponentAContext, { ComponentAProvider } from "./contexts/componentAContext"
ComponentA = (props) =>
ctx = useContext(ComponentAContext)
{ ... } = ctx
useEffect () =>
...
, [attr_changed]
<div>
Hello World
{props.children}
</div>
# just a wrapper for provider and component
ComponentAPackage = (props) =>
dup_props = Object.assign({}, props)
children = props.children
delete dup_props.children
<ComponentAProvider {...dup_props}>
<ComponentA>
{children}
</ComponentA>
</ComponentAProvider>
export { ComponentA, ComponentAPackage }
组件B
设置上下文/提供者
import React from "react"
ComponentBContext = React.createContext({})
export class ComponentBProvider extends React.Component
constructor: (props) ->
super(props)
this.state = {}
render: () ->
ctx = {
...
}
<ComponentBContext.Provider value={ Object.assign(ctx, this.state) }>
{this.props.children}
</ComponentBContext.Provider>
export default ComponentBContext
组件实际使用Context和Provider
import React, { useContext, useEffect } from "react"
import ReactDOM from 'react-dom'
import { ComponentAPackage } from 'componentA' # npm package
import ComponentBContext, { ComponentBProvider } from "./contexts/componentBContext"
ComponentB = () =>
ctx = useContext(ComponentBContext)
{ showCompA } = ctx
useEffect () =>
...
, [changed_attr]
if showCompA
<div>
With nested
<ComponentAPackage />
</div>
else
<div>Standalone</div>
class ComponentBPlugin
constructor: (configs, elm) ->
compB = <ComponentBProvider {...configs}><ComponentB /></ComponentBProvider>
ReactDOM.render compB, elm
this
export { ComponentBPlugin, ComponentB }
我尽量保持简单,但这有点复杂。因此,只需使用 new ComponentBPlugin({...}, elm) 运行 ComponentB 就可以了,但是将其添加到现有的 Ruby on Rails 项目 ComponentA barfs 就可以了,而 ComponentB 很好。如果我将<ComponentA /> 替换为<div />,则所有内容都会在rails 项目中呈现而不会出现错误。
Uncaught Error: Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
React 位于 ComponentA 和 ComponentB 的 peerDependencies 中,并且位于 Rails 项目的 package.json 中。他们都在期待react@16.13.1
Rails 项目 JS
{ ComponentBPlugin } = require("componentB") # installed npm package
setup = {...}
compB = new ComponentBPlugin setup, $(".some-div")[0]
我知道这里发生了很多事情,但我试图让一个遗留项目和一个新的 React 项目使用相同的组件和状态,并试图避免由于时间限制而重写太多并防止已经投入生产的遗留项目可能存在大量错误。
提前致谢
【问题讨论】:
标签: javascript ruby-on-rails reactjs react-hooks