
React + MUI + axios 실습에서 만난 다섯 가지 에러 대부분이 "값은 만들었지만 실제 사용처까지 연결을 안 한" 문제였고,
useState를 오해했던 것도 결국 같은 맥락이었다.
npm install @mui/material @emotion/react @emotion/styled
import Button from '@mui/material/Button';
그동안 개발하면서는 비슷한 버튼 동작을 직접 만들어 쓰고 있었는데, MUI라는 컴포넌트 라이브러리를 이번에 처음 제대로 써봤다!
https://mui.com/material-ui/getting-started/templates/
onClick이 동작하지 않음커스텀 컴포넌트(MaterialButton)가 props.onClick을 받기만 했지, 내부의 실제 MUI <Button>에는 연결하지 않았다.
// 수정 전
const MaterialButton = (props) => {
return <Button className='button'>{props.title}</Button>;
};
// 수정 후
const MaterialButton = (props) => {
return <Button className='button' onClick={props.onClick}>{props.title}</Button>;
};
핵심: props로 함수를 받는 것과, 그 함수를 실제 엘리먼트에 연결하는 것은 별개의 작업이다. 자동으로 연결되지 않음을 기억하기!
MUI는 emotion(CSS-in-JS)으로 <head>에 스타일을 런타임에 동적으로 삽입한다. 같은 specificity(우선순위)라면 나중에 삽입된 쪽이 이긴다 — 그래서 내가 처음에 커스텀하려고 만들었던 일반 .button 클래스가 무시됐다. mui의 개념에 대해서 잘 몰랐기 때문에 계속 css 코드 호출 문제인줄 알았다..
.button {
background-color: #2563eb !important;
border-radius: 2px !important;
}
!important로 임시 해결했지만, 정석은 sx prop이나 styled(Button)()을 쓰는 것. plain CSS 오버라이드는 로드 순서에 의존하는 임시방편이라는 걸 기억해두자!
// 부모
<Comment key={idx} data={comment}/>
// 자식 (수정 전) — data를 거치지 않고 최상위처럼 접근
<span>{props.writer}</span>
// 자식 (수정 후)
<span>{props.data.writer}</span>
부모는 data라는 이름 하나로 객체를 통째로 넘겼는데, 자식은 props.writer처럼 data를 건너뛰고 접근했다. 넘기는 이름과 읽는 경로는 항상 쌍으로 맞아야 한다. ({...comment}로 전개해서 넘겼다면 props.writer로 바로 접근 가능했음)
그리고 Comment 컴포넌트가 props를 받아야 하는 이유도 다시 정리했다 — .map()으로 3명(작성자별)의 서로 다른 데이터를 같은 컴포넌트로 렌더링해야 하기 때문. props라는 통로가 없으면 매번 같은 내용만 찍히고 재사용이 안 된다.

| 오해 | 실제 |
|---|---|
cnt = cnt + 1처럼 직접 재할당하면 값이 바뀐다 | 리렌더링이 안 일어나고, 다음 렌더에서 useState()가 다시 호출되며 값이 원래대로 돌아감. state는 "변수"가 아니라 리렌더링을 트리거하는 값 |
{cnt} + 1이 숫자 덧셈이다 | JS 표현식 자리에서 {cnt}는 객체 축약 표현({ cnt: cnt })으로 파싱됨 → "객체 + 1" 연산이 되어버림. 그냥 cnt + 1로 써야 함 |
useState()를 인자 없이 호출해도 된다 | 인자를 안 주면 초기값이 undefined, undefined + 1은 NaN. 상태 타입에 맞는 초기값(useState(0))을 항상 넣어야 함 |
const [cnt, setCnt] useState(); | = 빠뜨림 → 구조분해 할당은 const [a, b] = 표현식 형태가 필수, = 없으면 문법 에러 |
기억할 것:
setCnt(...))로만 한다.setCnt(prev => prev + 1){}는 문맥에 따라 객체 리터럴로 해석될 수 있다는 것을 주의한다.MaterialButton, Comment 컴포넌트 만들고 props 연결

axios.create() + json-server로 목 서버(5000번 포트) 연동
CapacityPage.jsx에서 카운트 증가 버튼 만들다가 위 useState 오해 4가지를 전부 만남
막힌 부분
CommentPage.jsx:7 GET http://localhost:3000/comment 404 (Not Found)
가장 헷갈렸던 건 axios baseURL 이슈였다. 콘솔에는 그냥 404만 찍혀서, 처음엔 백엔드(json-server)가 안 켜진 줄 알고 서버 쪽만 계속 확인했다.
★ 해결 방법
localhost:3000/comment로 나가고 있었음 — 기대한 5000이 아니었음)api/axios.js를 열어서 export default axios;로 원본을 내보내고 있는 걸 발견export default api;로 수정 후 정상 동작 확인