Sprawdzenie typów z wykorzystaniem PropTypes
Uwaga:
Z wersją Reacta v15.5
React.PropTypes
zostało przeniesione do innej paczki. Zamiast importować z paczki Reacta, używaj bibliotekiprop-types
.Dla ułatwienia migracji przygotowaliśmy skrypt codemod.
Wraz ze wzrostem rozmiaru twojej aplikacji, dzięki sprawdzaniu typów możesz wyłapać więcej błędów. W niektórych aplikacjach możesz korzystać z rozszerzeń JavaScriptu do sprawdzenia typów w całej aplikacji, takich jak Flow lub TypeScript. Nawet jeśli z nich nie korzystasz, możesz skorzystać z mechanizmu sprawdzania typów wbudowanego w Reacta. Aby rozpocząć sprawdzanie typów właściwości w komponencie, możesz dodać do komponentu specjalną właściwość propTypes
.
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Witaj, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
W powyższym przykładzie użyliśmy komponentu klasowego, jednak podobna zasada obowiązuje w przypadku komponentów funkcyjnych oraz komponentów tworzonych przy pomocy React.memo
lub React.forwardRef
.
PropTypes
eksportuje walidatory, które mogą być używane do sprawdzania poprawności danych wejściowych. W tym przypadku wykorzystujemy PropTypes.string
. Kiedy wartość przekazanej właściwości będzie nieprawidłowego typu, zostanie wyświetlone ostrzeżenie w konsoli javascriptowej. Ze względu na wydajność, propTypes
są sprawdzane tylko w trybie deweloperskim.
PropTypes
Oto przykład dokumentujący różne dostarczone walidatory:
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// Możesz zadeklarować, że właściwość będzie określonego typu javascriptowego.
// Domyślnie, wszystkie są opcjonalne.
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// Wszystko, co może być wyrenderowane: liczby, łańcuchy znaków, elementy czy tablice
// (lub fragmenty) zawierające te typy.
optionalNode: PropTypes.node,
// Element reactowy.
optionalElement: PropTypes.element,
// Typ komponenetu reactowego (np. MyComponent).
optionalElementType: PropTypes.elementType,
// Możesz także zadeklarować właściwość, która będzie instancją klasy.
// Wykorzystujemy do tego operator instanceof z JavaScriptu.
optionalMessage: PropTypes.instanceOf(Message),
// Możesz upewnić się, czy właściwość jest ograniczona do określonych wartości.
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// Właściwość może mieć też wiele typów.
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// Tablica zawierająca elementy określonego typu.
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// Obiekt zawierający wartości określonego typu.
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// Obiekt zawierający określone pola.
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// Obiekt zawierający tylko wskazane pola.
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// Możesz dodać do każdego z powyższych `isRequired`,
// aby sprawdzić, czy podana właściwość została zdefiniowana.
requiredFunc: PropTypes.func.isRequired,
// Wymagana wartość dowolnego typu danych.
requiredAny: PropTypes.any.isRequired,
// Możesz też utworzyć niestandardowy walidator. Powinien on zwracać obiekt `Error`,
// jeśli sprawdzenie zakończy się niepowodzeniem. Nie powinien wywoływać `console.warn`
// ani rzucać wyjątku, ponieważ nie będzie działał on wewnątrz `oneOfType`.
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Niepoprawna właściwość `' + propName + '` przekazana do ' +
' `' + componentName + '`. Walidacja zakończona niepowodzeniem.'
);
}
},
// Możesz także przekazać niestandardowy walidator do `arrayOf` i `objectOf`.
// Powinien on zwracać obiekt `Error`, jeśli sprawdzenie zakończy się niepowodzeniem.
// Walidator będzie wywoływany dla każdego klucza w tablicy lub obiekcie.
// Pierwsze dwa argumenty walidatora to walidowana tablica lub obiekt oraz klucz bieżącego elementu.
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Niepoprawna właściwość `' + propFullName + '` przekazana do ' +
' `' + componentName + '`. Walidacja zakończona niepowodzeniem.'
);
}
})
};
Wymaganie dokładnie jednego potomka
Wykorzystując PropTypes.element
możesz sprawdzić, czy do komponentu przekazano dokładnie jednego potomka.
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// Musi zawierać dokładnie jeden element. W przeciwnym wypadku zostanie wyświetlone ostrzeżenie.
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
Domyślne wartości właściwości
Możesz zdefiniować domyślne wartości dla właściwości przez przypisanie specjalnej właściwości defaultProps
:
class Greeting extends React.Component {
render() {
return (
<h1>Witaj, {this.props.name}</h1>
);
}
}
// Definiuje domyślne wartości dla właściwości:
Greeting.defaultProps = {
name: 'obcy'
};
// Renderuje "Witaj, obcy":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
Jeśli używasz babelowego transformatora plugin-proposal-class-properties (poprzednio plugin-transform-class-properties), możesz zadeklarować defaultProps
jako statyczną właściwość klasy komponentu reactowego. Ta składnia jeszcze nie została ukończona i do działania w przeglądarce będzie wymagać etapu kompilacji. Aby uzyskać więcej informacji, zobacz “class fields proposal”.
class Greeting extends React.Component {
static defaultProps = {
name: 'obcy'
}
render() {
return (
<div>Witaj, {this.props.name}</div>
)
}
}
Właściwość defaultProps
posłuży do zapewnienia wartości dla this.props.name
, jeśli nie zostanie ona określona przez komponent nadrzędny. Sprawdzanie typu propTypes
następuje po rozwiązaniu defaultProps
, więc sprawdzanie typu będzie miało zastosowanie także do defaultProps
.
Komponenty funkcyjne
Jeśli w swojej aplikacji regularnie korzystasz z komponentów funkcyjnych, musisz dokonać małych zmian, aby PropTypes zaczęły działać.
Załóżmy, że masz taki oto komponent:
export default function HelloWorldComponent({ name }) {
return (
<div>Witaj, {name}</div>
)
}
Aby dodać do niego PropTypes, zadeklaruj go osobno przed wyeksportowaniem:
function HelloWorldComponent({ name }) {
return (
<div>Witaj, {name}</div>
)
}
export default HelloWorldComponent
Teraz możesz dodać PropTypes bezpośrednio do HelloWorldComponent
:
import PropTypes from 'prop-types'
function HelloWorldComponent({ name }) {
return (
<div>Witaj, {name}</div>
)
}
HelloWorldComponent.propTypes = {
name: PropTypes.string
}
export default HelloWorldComponent