원티드 프론트엔드 프리온보딩 (22.12.19 월 ~ 23.01.20 금)
📍필요없는 것들은 제거하기
1️⃣불필요한 파일
Create React App 의 경우
- reportWebVitals 등..
2️⃣사용하지 않는 변수와 import 제거
- 뿐만 아니라, 사용하지 않는 라이브러리도 제거
📍상수화를 통한 가독성, 유지보수성 향상
예를 들어, signIn, signUp 같은 문자열 state에 따라 조건부 렌더링을 할 때,
Snake Case로 상수를 만들어 사용하는 것이 좋다
- 문자열을 전부 바꿔야 하는 경우가 있을 수 있는데, 하나만 놓쳐도 에러를 유발한다
- 상수는 변하지 않는 값이므로 state가 아님
- 예시
const SIGN_IN = "SIGN_IN"; // 최상단에 배치
const SIGN_UP = "SIGN_UP";
type RegisterMode = typeof SIGN_IN | typeof SIGN_UP
const Register = () => {
const navigate = useNavigate();
const [mode, setMode] = useState<RegisterMode>(SIGN_IN);
// ...
📍값이 필요하면 삼항 연산자, 분기가 필요하면 조건문
삼항 연산자 : 표현식
- 표현식은 값으로 평가된다
- As is
const handleClickRegisterChange = () => {
if (mode === SIGN_IN) {
setMode(SIGN_UP);
return;
}
setMode(SIGN_IN);
}
- To be
const handleClickRegisterChange = () => {
setMode(prevMode => prevMode === SIGN_IN ? SIGN_UP : SIGN_IN)
};
📍state의 최소 집합 찾기
React로 사고하기 – React
A JavaScript library for building user interfaces
ko.reactjs.org
가장 최소한의 state만 찾고, state에서 파생되는 값들은 즉석으로 계산해서 사용하자
- 예) TODO 아이템을 저장하는 배열만 state로 사용하고,
배열의 길이는 그냥 즉석으로 length를 써서 계산하기
이유
- state가 바뀌면 리렌더링이 발생한다
- 불필요한 리렌더링을 막아야 성능을 개선할 수 있다
- 예시
const [user, setUser] = useState<User>({
email: '',
password: '',
})
// 아래 state는 즉석으로 계산해서 사용하면 됨
const [userValidation, setUserValidation] = useState<UserValidation>({
email: false,
password: false,
})
📍가급적 코드 최상단에 가장 중요한 정보를 배치
- bad case
// Login.tsx
// 로그인 컴포넌트가 가급적 위에 나오는게 좋은데..
const LoginComponent = styled.div`
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
.menu {
display: flex;
width: 100%;
border: 1px solid black;
box-sizing: border-box;
border-bottom: none;
> div {
flex: 1;
text-align: center;
cursor: pointer;
padding: 10px 0;
}
.select {
background: #f5d042;
}
}
// ...
- styled components의 styled element는 최하단에 배치하는 것이 좋음
- 또한, css-in-js 방식과 일반 CSS 방식의 혼용을 지양해야함
📍무의미한 async/await 방지1
아래 코드에서는 굳이 async/await을 사용할 필요가 없다
- response 객체를 그대로 반환하기 때문에, 그냥 return문 뒤에 쓰면 됨
- As is
import { apiClient } from './auth';
const createTodo = async (body) => {
const res = await apiClient.post('/todos', body);
return res;
};
const getTodo = async () => {
const res = await apiClient.get('/todos');
return res;
};
const updateTodo = async (body, id) => {
const res = await apiClient.put(`/todos/${id}`, body);
return res;
};
const deleteTodo = async (id) => {
const res = await apiClient.delete(`/todos/${id}`);
return res;
};
export { createTodo, getTodo, updateTodo, deleteTodo };
// const todos = await getTodo();
- To be
import { apiClient } from './auth';
const createTodo = (body) => {
return apiClient.post('/todos', body);
};
const getTodo = () => {
return apiClient.get('/todos');
};
const updateTodo = (body, id) => {
return apiClient.put(`/todos/${id}`, body);
};
const deleteTodo = (id) => {
return apiClient.delete(`/todos/${id}`);
};
export { createTodo, getTodo, updateTodo, deleteTodo };
// const todos = await getTodo();
📍불필요한 catch 제거
- As is
const sumbitHandler = async (evt) => {
evt.preventDefault();
if (newTodo) {
await postTodos({ todo: newTodo })
.then((response) => {
dispatch({ type: 'ADD', todo: response });
})
.catch((err) => {
throw new Error(err); // 어차피 catch는 Error를 발생시키므로 불필요
// 여기서 예외처리할거면 예외처리 로직을 쓰고,
// 아니면 없애도 됨
});
inputRef.current.value = '';
inputRef.current.focus();
setNewTodo('');
}
};
- To be
const submitHandler = async (evt) => {
evt.preventDefault();
if (newTodo) {
const response = await postTodos({ todo: newTodo })
dispatch({type:"ADD", todo:response})
inputRef.current.value = '';
inputRef.current.focus();
setNewTodo('');
}
};