React.PropType 有两种可能的形状

React.PropType with two possible shapes

背景:我正在尝试为维度规范指定一个道具类型,我可以在其中指定一个显式值,或者要评估的最小值和最大值。这将由图像组件使用,该组件将评估图像是否是用户生成的输入可接受的高度和宽度。

The abstract goal is to have a React props value resolve to one of two possible shapes.


每个形状都有自己的作用

宽度的 显式值 将具有以下形状:

{
    width: PropTypes.shape({
        value: PropTypes.number.isRequired,
        error: PropTypes.string
    })
}

a min 和 max 值将具有以下形状:

{
    width: PropTypes.shape({
        min: {
            value: PropTypes.number.isRequired,
            error: PropTypes.string
        }, max: {
            value: PropTypes.number.isRequired,
            error: PropTypes.string
        }
    })
}

编辑:正如已接受的答案中所指出的,此块中有一个我没有发现的错误。出于某种原因,它没有给我一个 运行 时间错误,但这不是嵌套形状的工作示例,请参阅正确语法的答案。

如果我尝试这些方法中的任何一个并且属性匹配,一切都会按预期工作所以我可以放心地假设错误来自下面的代码


什么不起作用

我尝试使用 React typechecking documentation 中的 optionalUnion 通过 PropTypes.oneOfType 使用以下语法。

{
    width: PropTypes.oneOfType([
        PropTypes.shape({
            value: PropTypes.number.isRequired,
            error: PropTypes.string
        }), PropTypes.shape({
            min: {
                value: PropTypes.number.isRequired,
                error: PropTypes.string
            }, max: {
                value: PropTypes.number.isRequired,
                error: PropTypes.string
            }
        })
    ])
}

当我尝试这个时,我得到了回应

Warning: Failed propType: checker is not a function Check the render method of 'MyParentContainer'.

如果我在没有 PropTypes.oneOfType 方法的情况下使用任一形状,调试器中没有任何投诉,一切都如预期的那样 运行。 PropTypes.oneOf 抛出一个看似更严重的错误:

warning.js:45Warning: Failed propType: Invalid prop 'dimensions.width' of value '[object Object]' supplied to 'MyComponent', expected one of [null,null]. Check the render method of 'MyParentContainer'.

有谁知道此语法是否已关闭或者这是 PropTypes.oneOfType 的限制?这种问题有标准的解决方法吗?

PropTypes.shape 不是递归的,你必须对子结构重复它,例如

width: PropTypes.shape({
    min: PropTypes.shape({
        value: PropTypes.number.isRequired,
        error: PropTypes.string
    }).isRequired,
    max: PropTypes.shape({
        value: PropTypes.number.isRequired,
        error: PropTypes.string
    }).isRequired
})

因此,整个验证器应该是:

const propTypes = {
    width: PropTypes.oneOfType([
        PropTypes.shape({
            value: PropTypes.number.isRequired,
            error: PropTypes.string
        }),
        PropTypes.shape({
            min: PropTypes.shape({
                value: PropTypes.number.isRequired,
                error: PropTypes.string
            }).isRequired,
            max: PropTypes.shape({
                value: PropTypes.number.isRequired,
                error: PropTypes.string
            }).isRequired
        })
    ])
};

此外,我真的建议使用变量来增加可读性和防止代码重复:

const valueType = PropTypes.shape({
    value: PropTypes.number.isRequired,
    error: PropTypes.string
});

const propTypes = {
     width: PropTypes.oneOfType([
         valueType,
         PropTypes.shape({
             min: valueType.isRequired,
             max: valueType.isRequired
         })
     ])
 };