基本上我希望能够定义一个组件列表,这些组件可以直接位于组件层次结构中的子组件之上。有没有程序化的方法来检查这个?
该列表基本上是一个类数组,如
const allowed_parents = [Parent1, Parent2, Parent3];
接着
<UnListedParent>
.
.
.
<Child />
</UnListedParent>
应该抛出一个错误
基本上我希望能够定义一个组件列表,这些组件可以直接位于组件层次结构中的子组件之上。有没有程序化的方法来检查这个?
该列表基本上是一个类数组,如
const allowed_parents = [Parent1, Parent2, Parent3];
接着
<UnListedParent>
.
.
.
<Child />
</UnListedParent>
应该抛出一个错误
您不能使用任何已知的公共 React API 从子级直接访问父级。
当然,有一些“hacky”方法,例如,createRef
使用React.Children.map
和以React.cloneElement
编程方式将其传递给父级并将其传递给子级,但这是一个如此糟糕的设计,我什至不打算在这里发布它,以免成为与该代码相关联:D
不过,我认为更符合React
哲学和单向自上而下流程的更好方法是使用 HigherOrderComponent 包装的“允许的父母”的组合,将特定标志传递给他们“允许”的孩子,然后检查如果标志存在,则为 child,否则出现错误。
这可能大约是这样的
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
);