기본구조
컴포넌트를 사용해야하기때문에 확장자를 tsx로 두었다.
src
ㄴ App.tsx
ㄴ index.tsx
// index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// App.tsx
import React from "react";
const App = () => {
return (
<div>
</div>
);
};
export default App;
useState 사용하기
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState<number>(0);
const onIncrease = () => setCount(count + 1);
const onDecrease = () => setCount(count - 1);
return (
<div>
<h1>현재 숫자 : {count}</h1>
<div>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>+1</button>
</div>
</div>
);
};
export default Counter;
위와 같이 명확하게 useState 초기값이 정해져있다면 타입스크립트가 유추해서 잘 실행해서 상관없지만,
값이 어느것이 들어갈지 모를때는 제네릭을 명시해주는 것이 좋다.
// 값이 Information이 들어갈지 null일지 모를때.
type Information = { name: string; description: string };
const [info, setInformation] = useState<Information | null>(null);
상태가 까다로운 값이거나 구조가 어려운 형태일때도 제네릭을 명시해준다.
type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState<Todo[]>([]);
useState로 관리하는 입력값
타입스크립트라서 입력값을 받는 형식도 다 정해줘야 하는 것을 생각하면서 작성하면 좀 복잡해진다.
기본적인 리액트 구조를 알고나서 타입스크립트로 바꾼다고 생각하자.
import { useState } from "react";
type MyFormProps = {
onSubmit: (form: { name: string; apple: string }) => void;
};
function MyForm({ onSubmit }: MyFormProps) {
const [form, setForm] = useState({
name: "",
apple: "",
});
const { name, apple } = form;
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setForm({
...form,
[name]: value,
});
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSubmit(form);
setForm({
name: "",
apple: "",
}); // 초기화
};
return (
<form onSubmit={handleSubmit}>
<input name="name" value={name} onChange={onChange} />
<input name="apple" value={apple} onChange={onChange} />
<button type="submit">등록</button>
</form>
);
}
export default MyForm;
입력받는 값의 type을 지정해주고,
type MyFormProps = {
onSubmit: (form: { name: string; apple: string }) => void;
};
그 값을 사용하는 함수에 넣어주자.
// 함수형태기때문에 어떤 형식이든지 다 사용가능하다
function MyForm({ onSubmit }: MyFormProps){...}
const MyForm = ({ onSubmit }: MyFormProps) => {...}
onChange 함수에 넣을 값을 제네릭으로 선언해준다.
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setForm({
...form,
[name]: value,
});
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSubmit(form);
setForm({
name: "",
apple: "",
}); // 초기화
};
근데 React.ChangeEvent<HTMLInputElement> 이게 뭘까.
onChange의 이벤트의 인자값으로 들어갈거기때문에 이벤트 타입에 맞는 ChangEvent를 넣고,
해당 이벤트를 발생시키는 요소를 제네릭 값으로 넣으면 된다. (해당 설명 링크)
-라고 다들 설명하는데 이해는 잘 안가고, 우선 익숙해질때까지 사용해보는게 답일듯.
MyForm 컴포넌트를 App.tsx로 가져오면 다음과 같이 사용할 수 있다.
import React from "react";
import Counter from "./Counter";
import MyForm from "./MyForm";
const App: React.FC = () => {
const onSubmit = (form:{name:string; apple:string})=>{
console.log(form);
}
return (
<div>
<Counter />
<MyForm onSubmit={onSubmit} />
</div>
);
};
export default App;
useReducer 사용하기
useState로 만들었던 Counter를 useReducer로 만들어보자
// ReducerCount.tsx
import React, { useReducer } from "react";
type Action = { type: "INCREASE" } | { type: "DECREASE" };
const reducer = (state: number, action: Action): number => {
switch (action.type) {
case "INCREASE":
return state + 1;
case "DECREASE":
return state - 1;
default:
throw new Error("Unhandled action");
}
};
const ReducerCount = () => {
const [count, dispatch] = useReducer(reducer, 0);
const onIncrease = () => dispatch({ type: "INCREASE" });
const onDecrease = () => dispatch({ type: "DECREASE" });
return (
<div>
<h1>Reducer : {count}</h1>
<div>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
</div>
);
};
export default ReducerCount;
useRef 사용하기
리액트 컴포넌트에서 외부 라이브러리의 인스턴스 또는 DOM 을 특정 값 안에 담을 때 사용한다.
추가적으로, 이를 통해 컴포넌트 내부에서 관리하고 있는 값을 관리할 때 유용하다.
단, 이 값은 렌더링과 관계가 없어야 한다.
다음은 handleSubmit 이벤트가 등록 됐을 때 첫번째 인풋에 포커스가 잡히도록 만든 코드다.
import React, { useState, useRef } from "react";
type MyFormProps = {
onSubmit: (form: { name: string; apple: string }) => void;
};
const MyForm = ({ onSubmit }: MyFormProps) => {
const inputRef = useRef<HTMLInputElement>(null);
const [form, setForm] = useState({
name: "",
apple: "",
});
const { name, apple } = form;
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setForm({
...form,
[name]: value,
});
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSubmit(form);
setForm({
name: "",
apple: "",
}); // 초기화
// 리액트 컴포넌트에서 외부 라이브러리의 인스턴스 또는 DOM 을 특정 값 안에 담을 때 사용
// 이를 통해 컴포넌트 내부에서 관리하고 있는 값을 관리할 때 유용하죠. 단, 이 값은 렌더링과 관계가 없어야 합니다
if (!inputRef.current) {
return;
}
inputRef.current.focus();
};
return (
<form onSubmit={handleSubmit}>
<input name="name" value={name} onChange={onChange} ref={inputRef} />
<input name="apple" value={apple} onChange={onChange} />
<button type="submit">등록</button>
</form>
);
};
export default MyForm;
아래는 inputRef값을 사용하기 위해 입력값이 null체킹을 하는 코드다.
타입스크립트에서 만약 어떤 타입이 undefined 이거나 null 일 수 있는 상황에는, 해당 값이 유효한지 체킹하는 작업을 꼭 해주어야 자동완성도 잘 이루어지고, 오류도 사라진다.
if (!inputRef.current) {
return;
}
이 블로그 정리 잘 되어있어서 이해하기 쉬웠다.
'프로그래밍 > react' 카테고리의 다른 글
React-Slick로 회전메뉴(Carousel/캐러셀 사용하기) (0) | 2022.11.09 |
---|---|
Expected an assignment or function call and instead saw an expression (0) | 2022.10.31 |
Uncaught TypeError: function is not iterable (cannot read property Symbol(Symbol.iterator)) (0) | 2022.10.27 |
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'call') at Hmac.CipherBase (0) | 2022.10.26 |
리액트로 동적라우팅 구현하기 (0) | 2022.10.24 |
댓글