反应 PropTypes - 或者

React PropTypes - OR

对于此代码:

const FirstComponentPropTypes = {
   foo: PropTypes.any,
};

const SecondComponentPropTypes = {
   bar: PropTypes.any,
};

...

function MyComponent({ foo, bar }) {
   if (foo) {
     return <FirstComponent foo={foo} />;
   } else if (bar) {
     return <SecondComponent bar={bar} />;
   }
   
   throw new Error("Invalid props.");
}

为了设置 MyComponentpropTypes,是否可以这样做:

MyComponent.propTypes = FirstComponentPropTypes | SecondComponentPropTypes;

?

我假设您的意思是 | 是因为您想对这两个集合求并集?您可以将这两个对象合并为 Object.assign():

const FirstComponentPropTypes = {
   foo: PropTypes.any,
};

const SecondComponentPropTypes = {
   bar: PropTypes.any,
};

function MyComponent({ foo, bar }) { ... }

MyComponent.propTypes = Object.assign({}, SecondComponentPropTypes, FirstComponentProptypes);

正如您所指出的:

MyComponent is a "generic" component which renders A if foo is present or B if bar is present.

它的定义是function MyComponent({ foo, bar }) { ... }

为了避免复杂的解决方案,我建议您将条件逻辑移到 MyComponent 之外。这样,您将需要 MyComponent 的单个 propType 定义,而无需复制其他两个组件的 propType 定义。您的组件将检查的类型是 element,这是所有 React 元素共享的通用类型。

MyComponent.propTypes = {
    elementToRender: PropTypes.element
};

因此您需要调整您的组件定义:

function MyComponent({ elementToRender }) { ... }

及其使用方式:

const getComponentToRender = (foo, bar) => {
   if (foo) {
     return <FirstComponent foo={foo} />;
   } else if (bar) {
     return <SecondComponent bar={bar} />;
   } else {
     return null;
   }
}

const element = getComponentToRender(foo, bar)

你的 jsx:

{!element && <YourErrorComponent />}
{element && <MyComponent elementToRender={element} />}

如果需要,您始终可以在不使用常量或变量的情况下将条件逻辑放入组件中。

好处

这种方法的最大好处是您的 MyComponent 不需要了解您的 FirstComponentSecondComponent 类型的任何信息。并且您始终可以选择使用另一个组件传递给 MyComponent 而无需更改它。

此外,您在定义类型的代码中只有一个点,它们之间没有任何依赖关系。

另外,你也不是在一个点上获得道具,然后在远离它的情况下使用它们。

最后的考虑

为了让您的代码易于阅读,我建议您避免对元素使用特定的 prop。使用 props.children 代替:

    {element && <MyComponent>{element}</MyComponent>}

这是一种更React-ish自然)的方式来显示另一个组件内的组件:children 道具就是为了这个目的而存在的。

此外,您可以(再次)在 MyComponent 中放置回退逻辑:

function MyComponent({ children }) {
    if (children) {
        return <div className="container">{children}</div>
    }
    
    return <p>children is missing</>
}