Не так давно мой техлид на проекте сказал о том, что есть необязательная, но весьма специфичная и в то же время интересная задача: нужно сделать Error Boundary для обработки неверно пришедших props в компонент. Я на радостях за нее взялся с уверенностью, что в документации уже точно есть такое решение.
Думаю, вы уже поняли, что не все оказалось так просто.
Несколько часов серфинга не дали абсолютно никаких результатов и я осознал, что мне придется лезть внутрь пакета prop-types.
На самом деле было сложно понять, что там творится внутри, но все-таки мое внимание кое-что привлекло, а именно константа ReactPropTypesSecret в одноименном файле:
Звучит угрожающе, правда?
Я долго не мог понять, что же значит эта константа. Сначала я подумал, что это просто какая-то забавная пасхалка от Facebook, но не тут-то было, у нее и в самом деле есть смысл!
В файле factoryWithTypeCheckers.js я нашел функцию checkType, которая по сути является тем самым валидатором, который кидает warning в консоль, если в компонент пришли неверные props:
Обратите внимание на последний аргумент! Если последним аргументом в эту функцию передать константу из файла ReactPropTypesSecret.js, то вместо warning в консоль функция будет возвращать объект ошибки неверных props, либо null, если все верно.
И уже это можно использовать для того, чтобы создать компонент-обработчик ошибок для неверных props.
На основе полученных мной знаний я создал простейший HOC, который можно использовать как Error Boundary для любого компонента. Выглядит он так:
Сначала мы вызываем для каждого прописанного propType у компонента функцию-валидатор, затем убираем из полученного массива null, извлекаем сообщения ошибок и вуаля — обработка ошибок готова!
Думаю, вы уже поняли, что не все оказалось так просто.
Несколько часов серфинга не дали абсолютно никаких результатов и я осознал, что мне придется лезть внутрь пакета prop-types.
На самом деле было сложно понять, что там творится внутри, но все-таки мое внимание кое-что привлекло, а именно константа ReactPropTypesSecret в одноименном файле:
var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
Звучит угрожающе, правда?
Я долго не мог понять, что же значит эта константа. Сначала я подумал, что это просто какая-то забавная пасхалка от Facebook, но не тут-то было, у нее и в самом деле есть смысл!
В файле factoryWithTypeCheckers.js я нашел функцию checkType, которая по сути является тем самым валидатором, который кидает warning в консоль, если в компонент пришли неверные props:
function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
Обратите внимание на последний аргумент! Если последним аргументом в эту функцию передать константу из файла ReactPropTypesSecret.js, то вместо warning в консоль функция будет возвращать объект ошибки неверных props, либо null, если все верно.
И уже это можно использовать для того, чтобы создать компонент-обработчик ошибок для неверных props.
На основе полученных мной знаний я создал простейший HOC, который можно использовать как Error Boundary для любого компонента. Выглядит он так:
import React from ‘react’;
import SECRET from ‘prop-types/lib/ReactPropTypesSecret’;
const propTypesChecker = (Component) => (props) => {
const analysis = Object.keys(Component.propTypes).map((key) => {
// Здесь мы получим одну из функций-валидаторов. Например, PropTypes.number
const validator = Component.propTypes[key];
// Вызов валидатора с передачей константы-секрета последним аргументом
return validator(props, key, Component.name, ‘’, null, SECRET);
});
// Извлекаем сообщения об ошибках
const errors = analysis.filter((error) => error !== null).map((error) => error.message);
const arePropsValid = errors.length === 0;
// Компонент/элемент, переданный в props, который должен отобразиться в случае неверно пришедших props
const ErrorBoundary = props.errorBoundary;
return (
arePropsValid
? <Component {…props} />
: <ErrorBoundary errors={errors} />
);
};
export default propTypesChecker;
Сначала мы вызываем для каждого прописанного propType у компонента функцию-валидатор, затем убираем из полученного массива null, извлекаем сообщения ошибок и вуаля — обработка ошибок готова!