Javascript 确保组件只能是特定父组件的子组件

Javascript 确保组件只能是特定父组件的子组件,javascript,reactjs,Javascript,Reactjs,基本上,我希望能够定义一个组件列表,该列表可以位于组件层次结构中子组件的正上方。是否有一种程序化的方法来检查这一点 该列表基本上是一个类数组,如 const allowed_parents = [Parent1, Parent2, Parent3]; 然后 <UnListedParent> . . . <Child /> </UnListedParent> . . . 如果抛出错误您无法使用任何已知的公共API从子级直接访问父级 当然

基本上,我希望能够定义一个组件列表,该列表可以位于组件层次结构中子组件的正上方。是否有一种程序化的方法来检查这一点

该列表基本上是一个类数组,如

const allowed_parents  = [Parent1, Parent2, Parent3];
然后

<UnListedParent>
  .
  .
  .
  <Child />
</UnListedParent>

.
.
.

如果抛出错误

您无法使用任何已知的公共API从子级直接访问父级

当然也有一些“黑客”方法,比如,在父对象上使用
React.Children.map
React.cloneElement
以编程方式创建ref并将其传递给子对象,但这是一个非常糟糕的设计,我甚至不打算在这里发布它,因为它与该代码没有关联:D

不过,我认为更好的方法与
React
理念和单向自上而下的流程相一致,就是使用高阶组件包装的“允许的父母”的组合,将特定的标志传递给他们“允许”的孩子,然后检查孩子是否存在标志,否则会出错

大概是这样的

import React,{useState}来自“React”;
从“react dom”导入react dom;
常量Child=({isAllowed})=>{
如果(!不允许){
抛出新错误(“我们不被允许!”);
}
归还一个被允许的孩子。;
};
常量allowParentHOC=Wrapper=>{
返回({children,…props})=>{
返回(
{React.Children.map(Children,child=>
反应。克隆元素(儿童{
我承认:是的
})
)}
);
};
};
常量Parent1=allowParentHOC(props=>);
constparent2=allowParentHOC(props=>);
const UnListedParent=({children})=>children;
类ErrorBoundary扩展了React.Component{
状态={hasError:false};
componentDidCatch(错误,信息){
this.setState({hasError:true,info});
}
render(){
if(this.state.hasError){
//您可以呈现任何自定义回退UI
返回(
这孩子的位置不好:(
{JSON.stringify(this.state.info,null,2)}
);
}
返回此.props.children;
}
}
类应用程序扩展了React.Component{
状态={
IsUnallowedParentShowed:false
};
handleToggle=()=>
this.setState({IsUnallowedParentShowed})=>({
IsUnallowedParentShowed:!IsUnallowedParentShowed
}));
render(){
返回(
切换版本
{this.state.isunallowedparentshow(
) : (
)}
);
}
}
导出默认应用程序;
const rootElement=document.getElementById(“根”);
ReactDOM.render(
,
根元素
);

您可以使用任意数量的测试库来检查这一点。Jest是React的常用选择。如果您在
const UnlistedParent=()=>
格式是否正确?这意味着它也是一个孩子,只是不在JSX树中。@jmargolisvt我明白了,我将查看jest api,看看是否有可能检查它。@gazdagergo否,因为这将使
孩子
成为
未受限制父母
的直接孩子。基本上,我想确保孩子只有在不受限制的情况下才能使用包装在列出的父组件中这是一个测试问题?或者您是否询问是否有可能在主运行时检查它?我的ListedParent不会使用
props.children
,在它们下面的子组件中迭代。因此,我想确保子组件只能在ListedParent下面立即使用。
import React, { useState } from "react";
import ReactDOM from "react-dom";

const Child = ({ isAllowed }) => {
  if (!isAllowed) {
    throw new Error("We are not allowed!");
  }

  return <div>An allowed child.</div>;
};

const allowParentHOC = Wrapper => {
  return ({ children, ...props }) => {
    return (
      <Wrapper {...props}>
        {React.Children.map(children, child =>
          React.cloneElement(child, {
            isAllowed: true
          })
        )}
      </Wrapper>
    );
  };
};

const Parent1 = allowParentHOC(props => <div {...props} />);
const Parent2 = allowParentHOC(props => <div {...props} />);

const UnListedParent = ({ children }) => children;

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  componentDidCatch(error, info) {
    this.setState({ hasError: true, info });
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return (
        <>
          <h1>This Child was not well put :(</h1>
          <pre>{JSON.stringify(this.state.info, null, 2)}</pre>
        </>
      );
    }
    return this.props.children;
  }
}

class App extends React.Component {
  state = {
    isUnAllowedParentShown: false
  };

  handleToggle = () =>
    this.setState(({ isUnAllowedParentShown }) => ({
      isUnAllowedParentShown: !isUnAllowedParentShown
    }));

  render() {
    return (
      <>
        <button onClick={this.handleToggle}>Toggle Versions</button>
        {this.state.isUnAllowedParentShown ? (
          <UnListedParent>
            <Child />
          </UnListedParent>
        ) : (
          <>
            <Parent1>
              <Child />
            </Parent1>
            <Parent2>
              <Child />
            </Parent2>
          </>
        )}
      </>
    );
  }
}

export default App;

const rootElement = document.getElementById("root");
ReactDOM.render(
  <ErrorBoundary>
    <App />
  </ErrorBoundary>,
  rootElement
);