บันทึกความเข้าใจจาก
React ไปวันๆ EP.4 - Typescript in React 101
React-in-Thai / react-ts-101
สิ่งที่ควรต้องรู้ในการเขียน react ด้วย typescript
This project was bootstrapped with Create React App.
Purpose
This project is designed for people who want to upskill from JavaScript to TypeScript to write code better.
Recommended for people who just started using TypeScript!
Contributing
Feel free to send PR or contact siriwat if you have more awesome ideas.
Topic
- UseState
- Promise
- Chidren Types
- Compound Component
- Bye Bye Enum
- React & html type that you should know
- CSS type
Why TypeScript
เมื่อก่อน JavaScript ถูกก design ให้ใช้งานง่ายๆสำหรับ brower แต่ตอนนี้มันอยู่ทุกส่วนแล้ว
Type
เหมือน interface แต่สามารถกำหนดชื่อให้ primitives type ได้ ใช้ในรูป unions ได้ ในรูป tuples ได้
Tuple คืออะไร
Tuple เป็น Data Structure แบบหนึ่งที่เป็น Array แบบ Fixed Size โดยที่ Data ที่อยู่ภายใน Tuple ไม่จำเป็นต้องเป็น Type ชนิดเดียวกันunions คืออะไร ดูข้างล่างนี้
type User = {
firstname: string;
lastname: string;
};
type NumberOrStringOrStudent = string | number | User;
let myValue: NumberOrStringOrStudent;
const sampleUser: User = {
firstname: "Sippakorn",
lastname: "Raksakiart",
};
// ประกาศ Tuple
let option: [string, boolean, number];
option = ["uppercase", true, 1]; // OK
option2 = [false, 2, "lowercase"]; // ERROR
UseState
export type ProfileProps = {
name: string,
age: number,
};
// todo: create Prop type for this component, also optional type
export function BasicProps({ name, age }: ProfileProps) {
return (
<div>
<div>Name: {name}</div>
<div>Age: {age}</div>
</div>
);
}
ถ้าอยากได้แบบ optional ละก็เพิ่ม ?
export type ProfileProps = {
name?: string,
age?: number,
};
const [boolOrNum, setBoolOrNum] = useState();
const [boolOrNum, setBoolOrNum] = useState<boolean | number>(); // need to be boolean | number
<button
onClick={() =>
setBoolOrNum((c) => {
if (typeof c === "number") {
return c + 1;
}
})
}
>
Increment
</button>;
อย่าลืมที่จะใส่ Item[]
interface Item {
id: string
name: string
}
export function Example2() {
const [data, setData] = useState<Item[]>([]);
return data.map((item, i) => (
<div>
Item {i} is {item.id}
</div>
));
}
Promise
ดูนาทีที่ 45.00
import React, { useEffect, useState } from "react";
import { getData } from "../js/api";
const api = (id: string) => new Promise<string>((resolve, reject) => {});
// todo : create custom hook that set response from api to state and return the state
function useData(id: number) {
const [data, setData] = useState<number>();
useEffect(() => {
(async function () {
setData(await getData(id));
})();
}, [id]);
return data;
}
// what if api dont have type?
จากข้างบนเราจะไม่รู้ว่า getData เป็น type อะไร เราอาจจะใส่ type ให้มันด้วยก็ได้
หรือไม่ก็ได้เพราะ reusult ออกไปก็ถูกต้องอยู่ดี
Chidren types
เข้าไปดู React.ReactNode
type ReactChild = ReactElement | ReactText;
type ReactNode =
| ReactChild
| ReactFragment
| ReactPortal
| boolean
| null
| undefined;
interface ReactElement<
P = any,
T extends string | JSXElementConstructor<any> =
| string
| JSXElementConstructor<any>
> {
type: T;
props: P;
key: Key | null;
}
เข้าไปดู PropsWithChildren
(นาที52)
type PropsWithChildren<P> = P & { children?: ReactNode };
หรือเราจะเขียน render prop
import React from "react";
type Props = {
header: React.ReactNode; // can react Children
sidebar: React.ReactElement; // jsx
footer: string;
render: (value: boolean) => React.ReactNode;
};
export function Example({
header,
sidebar,
footer,
children,
}: React.PropsWithChildren<Props>) {
const [state, setState] = useState(false);
return (
<div>
<header>{header}</header>
<div>{sidebar}</div>
<div>{children}</div>
<footer>{footer}</footer>
{render(state)}
</div>
);
}
Compound component
มาดูกันว่าแบบนี้จะเขียน type ได้อย่างไร
// Grid.tsx
import React from "react";
// todo : create Grid component that contain Row & Column
// outside
function App() {
return (
<Grid.Row>
<Grid.Column>
<div>Content 1</div>
</Grid.Column>
<Grid.Column>
<div>Content 2</div>
</Grid.Column>
</Grid.Row>
);
}
เพิ่มอันนี้เข้าไป
const Grid = ({ children }: React.PropsWithChildren<{}>) => {
return <div>{children}</div>;
};
const Row = ({ children }: React.PropsWithChildren<{}>) => {
return <div>{children}</div>;
};
const Column = ({ children }: React.PropsWithChildren<{}>) => {
return <div>{children}</div>;
};
// อย่าลืมที่ขะบอกว่า Row อยู่ใน Grid
Grid.Row = Row;
Grid.Column = Column;
หรือจะทำแบบนี้แทนก็ได้ (นาทที่1hr.02 ผมเองก็ยังไม่เข้าใจจุดนี้)
interface Grid {
({ children }: React.PropsWithChildren<{}>): React.ReactNode;
Row: typeof Row;
Column: typeof Column;
}
const Grid: Grid = () => {
return <div />;
};
Bye Bye Enum
นาทีที่ 1hr.04
import React from "react";
enum Colors {
Red = "red",
Blue = "blue",
Green = "green",
White = "white",
}
type Props = {
color: Colors;
};
นอกจากนี้ท่าที่ทำไม่ได้
cons c1:Color = 'red'
//ต้องใช้ท่านี้
const c1 = 'red' as Colors
หรือจะทำเป็น Object
const Colors = {
Red: 'red'
Blue: 'blue'
}
type Prop ={
color:Colors // มันจะ error บอกว่าเอา Object มาทำ Type ไม่ได้
}
ต้องแปลง Object เป็น type
const Colors = {
Red: 'red'
Blue: 'blue'
}
//typeof Colors = (typeof Colors) // ได้ struct Colors ละ
typeof Colors = (typeof Colors)[keyof typeof Colors] //return key
code จะใช้ได้เหมือน enum
const Colors = {
Red: "red",
Blue: "blue",
} as const;
type Colors = typeof Colors[keyof typeof Colors];
type Props = {
color: Colors;
};
เราสามารถทำง่ายกว่านี้โดยใช้ enum
const Colors = {
Red: "red",
Blue: "blue",
} as const;
type Enum<T> = T[keyof T];
type Colors = Enum<typeof Colors>;
type Props = {
color: Colors;
};
ต่อจากนี้จะเป็น part 2
⚛️ React ไปวันๆ EP.5 - Typescript in React 101 part 2
React & html type that you should know
ลองดูตัวอย่างต่อไปนี้ที่จำทำให้ cursor ไป focus ที่ input
import React, { useRef, useEffect } from "react";
// todo : create input that will be focused if autoFocus prop is true
function Example({ autoFocus }: { autoFocus?: boolean }) {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<form>
<label htmlFor="input">Label</label>
<input id="input" ref={inputRef} />
</form>
);
}
แต่มันยังผิดอยู่ต้องเพิ่ม HtmlInputElement
เพิ่ม optinal auto ให้ด้วย
import React, { useRef, useEffect } from "react";
// todo : create input that will be focused if autoFocus prop is true
function Example({ autoFocus }: { autoFocus?: boolean }) {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, [autoFocus ]);
return (
<form>
<label htmlFor="input">Label</label>
<input id="input" ref={inputRef} />
</form>
);
}
Top comments (0)