reactjs - TypeScript kullanarak React bileşeninde varsayılan özellik değeri
Typescript kullanarak bileşenlerim için varsayılan özellik değerlerini nasıl ayarlayacağımı çözemedim.
Bu kaynak kodudur:
class PageState
{
}
export class PageProps
{
foo: string = "bar";
}
export class PageComponent extends React.Component<PageProps, PageState>
{
public render(): JSX.Element
{
return (
<span>Hello, world</span>
);
}
}
Ve bileşeni şöyle kullanmaya çalıştığımda:
ReactDOM.render(<PageComponent />, document.getElementById("page"));
Bir hata alıyorum, foo özelliğinin eksik olduğunu söylüyor. Varsayılan değeri kullanmak istiyorum. Ayrıca komponentin içinde static defaultProps=... kullanmayı da denedim, ama tahmin ettiğim gibi etkisi olmadı.
src/typescript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.
Varsayılan özellik değerlerini nasıl kullanabilirim? Şirketimin kullandığı birçok JS bileşeni bunlara dayanıyor ve kullanmamak bir seçenek değil.
Cevap #1
Sınıf bileşeni ile varsayılan özellikler
static defaultProps kullanmak doğrudur. Ayrıca props ve state için sınıflar yerine arayüzler kullanmalısınız.
Güncelleme 2018/12/1: TypeScript zamanla defaultProps ile ilgili tip denetimini geliştirdi. En son ve en iyi kullanımlardan eski kullanım ve sorunlara kadar okumaya devam edin.
TypeScript 3.0 ve sonrası için
TypeScript, tür denetiminin beklendiğiniz şekilde çalışmasını sağlamak için özellikle defaultProps desteği ekledi. Örnek:
interface PageProps {
foo: string;
bar: string;
}
export class PageComponent extends React.Component<PageProps, {}> {
public static defaultProps = {
foo: "default"
};
public render(): JSX.Element {
return (
<span>Hello, { this.props.foo.toUpperCase() }</span>
);
}
}
Hangisi bir foo özniteliği geçmeden render edilebilir ve derlenebilir:
<PageComponent bar={ "hello" } />
Dikkat edin ki:
fooJSX özniteliği olarak zorunlu olmasa da (yanifoo?: string) opsiyonel olarak işaretlenmemiştir. Opsiyonel olarak işaretlemek,undefinedolabileceği anlamına gelir, ancak aslındaundefinedolmayacaktır çünküdefaultPropsbir varsayılan değer sağlar. Bunu, bir işlev parametresini opsiyonel veya varsayılan bir değerle işaretleyebileceğiniz, fakat her ikisini birden yapamayacağınız duruma benzetebilirsiniz; ancak her iki durumda da çağrının bir değer belirtmesini gerektirmez. TypeScript 3.0+defaultProps'i benzer bir şekilde ele alır, bu da React kullanıcıları için gerçekten harika!defaultPropsiçin açık bir tür bildirimi yoktur. Türü çıkarılır ve hangi JSX özniteliklerinin gerekli olduğunu belirlemek için derleyici tarafından kullanılır.defaultProps: Pick<PageProps, "foo">kullanarakdefaultProps'unPageProps'un bir alt kümesiyle eşleşmesini sağlayabilirsiniz. Bu uyarının detayları burada açıklanmıştır.- Bu, doğru çalışması için
@types/reactsürüm16.4.11'i gerektirir.
TypeScript 2.1'den 3.0'a kadar
TypeScript 3.0, defaultProps için derleyici desteği uygulamadan önce, yine de bundan yararlanabiliyordunuz ve çalışma zamanında React ile %100 çalışıyordu, ancak TypeScript JSX özniteliklerini kontrol ederken sadece props'ları dikkate aldığı için, varsayılan değere sahip props'ları ? ile isteğe bağlı olarak işaretlemeniz gerekiyordu. Örnek:
interface PageProps {
foo?: string;
bar: number;
}
export class PageComponent extends React.Component<PageProps, {}> {
public static defaultProps: Partial<PageProps> = {
foo: "default"
};
public render(): JSX.Element {
return (
<span>Hello, world</span>
);
}
}
Dikkat edin ki:
- Varsayılan değerlerinizi prop'larınızla tür denetimi yapacak şekilde tip kontrolünden geçirmek için
defaultProps'iPartial<>ile not etmek iyi bir fikirdir, ancak her gerekli özelliği bir varsayılan değer ile sağlamak zorunda değilsiniz; çünkü gerekli özelliklerin asla varsayılan değere ihtiyacı olmamalıdır. strictNullCheckskullanıldığındathis.props.foodeğeriolası undefinedolacaktır veundefined'i kaldırmak için bir null olmayan doğrulaması (örn.this.props.foo!) veya tip koruması (örn.if (this.props.foo) ...) gerektirir. Bu sinir bozucudur çünkü varsayılan prop değeri aslında hiçbir zaman undefined olmayacağı anlamına gelir, ama TS bu akışı anlamadı. İşte bu, TS 3.0'ındefaultPropsiçin açık destek eklemesinin başlıca nedenlerinden biridir.
TypeScript 2.1 Öncesinde
Bu aynı şekilde çalışır ama Partial türlerine sahip değilsiniz, bu yüzden sadece Partial<> öğesini atlayın ve tüm gerekli özellikler için varsayılan değerler sağlayın (bu varsayılanlar asla kullanılmayacak olsa bile) veya açık tür açıklamasını tamamen atlayın.
Fonksiyonel Bileşenlerle Varsayılan Özellikler
Fonksiyon bileşenlerinde de defaultProps kullanabilirsiniz, ancak TypeScript'in fonksiyon üzerindeki defaultProps'u bilmesi için fonksiyonunuzu FunctionComponent (16.7.2'den önce @types/react'te StatelessComponent) arayüzüne göre tip vermeniz gerekir:
interface PageProps {
foo?: string;
bar: number;
}
const PageComponent: FunctionComponent<PageProps> = (props) => {
return (
<span>Hello, {props.foo}, {props.bar}</span>
);
};
PageComponent.defaultProps = {
foo: "default"
};
TS 2.1+'da FunctionComponent.defaultProps zaten bir kısım olarak belirtildiğinden, Partial<PageProps>'ı herhangi bir yerde kullanmanız gerekmediğini unutmayın.
Bir diğer güzel alternatif (benim kullandığım) props parametrelerinizi yapısal olarak ayırmak ve varsayılan değerleri doğrudan atamaktır:
const PageComponent: FunctionComponent<PageProps> = ({foo = "default", bar}) => {
return (
<span>Hello, {foo}, {bar}</span>
);
};
O zaman defaultProps'a hiç ihtiyacınız yok! Dikkat edin, eğer bir fonksiyon bileşeninde defaultProps sağlarsanız, bu varsayılan parametre değerlerinin önüne geçer, çünkü React her zaman defaultProps değerlerini açıkça geçirir (bu yüzden parametreler hiç undefined olmaz, dolayısıyla varsayılan parametre hiç kullanılmaz.) Yani ikisini birden değil, birini kullanırsınız.
Cevap #2
Typescript 2.1+ ile, arayüzünüzün özelliklerini isteğe bağlı yapmak yerine Partial < T > kullanın.
export interface Props {
obj: Model,
a: boolean
b: boolean
}
public static defaultProps: Partial<Props> = {
a: true
};
Cevap #3
Fonksiyonel Bileşen
Aslında, fonksiyonel bileşen için en iyi uygulama aşağıdaki gibidir, bir örnek Spinner bileşeni oluşturdum:
import React from 'react';
import { ActivityIndicator } from 'react-native';
import { colors } from 'helpers/theme';
export interface SpinnerProps {
color?: string;
size?: 'small' | 'large' | 1 | 0;
animating?: boolean;
hidesWhenStopped?: boolean;
}
const Spinner = ({
color = colors.primary,
size = 'small',
animating = true,
hidesWhenStopped = true,
}: SpinnerProps): JSX.Element => (
<ActivityIndicator
color={color}
size={size}
animating={animating}
hidesWhenStopped={hidesWhenStopped}
/>
);
export default Spinner;
Bileşeninizin children özelliği varsa, aşağıdaki gibi React.FC kullanmanız daha iyi olur:
export interface TypographyProps {
color?: string;
}
const Typography: React.FC<TypographyProps> = ({
children,
color,
}) => (
<span style={{ color }}>
{children}
</span>
);
export default Typography;
Cevap #4
Standart bir fonksiyonel bileşende özellikleri yeniden atamak için spread operatörünü kullanabilirsiniz. Bu yaklaşımda hoşuma giden şey, gerekli özellikleri varsayılan değere sahip isteğe bağlı olanlarla karıştırabilmenizdir.
interface MyProps {
text: string;
optionalText?: string;
}
const defaultProps = {
optionalText = "foo";
}
const MyComponent = (props: MyProps) => {
props = { ...defaultProps, ...props }
}
Cevap #5
Typescript 3.0 ile bu soruna yeni bir çözüm var:
export interface Props {
name: string;
}
export class Greet extends React.Component<Props> {
render() {
const { name } = this.props;
return <div>Hello ${name.toUpperCase()}!</div>;
}
static defaultProps = { name: "world"};
}
// Type-checks! No type assertions needed!
let el = <Greet />
Bunun çalışması için @types/react'in 16.4.6'dan daha yeni bir sürümüne ihtiyacınız olduğunu unutmayın. 16.4.11 ile çalışır.
