[WEB-007][중급] 상태를 바꾸고 화면을 다시 그리기
페이지 정보

본문
[이번 수업]
버튼을 눌렀는데 숫자와 버튼 상태가 어긋나면 데이터와 화면의 갱신 위치가 흩어진 경우가 많습니다. 이번에는 상태를 한곳에 두고 `render()`로 화면을 갱신합니다.
[선수지식]
WEB-001의 HTML, WEB-004의 버튼 접근성, WEB-005의 DOM과 클릭 이벤트를 알고 JavaScript를 실행할 수 있어야 합니다.
[학습목표]
1. 상태와 렌더링을 쉬운 말로 설명한다.
2. 이벤트 → 상태 변경 → 렌더링 흐름을 구현한다.
3. 화면 요소를 상태 원본처럼 읽는 실수를 피한다.
[핵심개념]
상태(state)는 시간이 지나며 바뀌고 화면에 영향을 주는 데이터입니다. 로그인 여부, 수량, 선택한 탭이 예입니다. 렌더링(rendering)은 현재 상태를 DOM 속성·텍스트·스타일로 반영하는 과정입니다. DOM(Document Object Model)은 HTML 문서를 JavaScript가 다룰 수 있는 노드 트리로 표현한 모델입니다.
기본 흐름은 “사용자 이벤트 → 상태 계산 → `render()` 호출 → 화면 동기화”입니다. 상태를 단일 진실 공급원으로 관리하면 숫자와 버튼 활성 여부가 어긋날 가능성이 줄어듭니다. `render()`는 상태만 읽어 화면을 갱신하고 상태는 바꾸지 않게 나눕니다. 같은 상태로 여러 번 호출해도 같은 화면이 나오는 것이 좋습니다.
화면 텍스트를 다시 읽어 상태로 쓰면 수정 위치가 늘수록 어긋나기 쉽습니다. 기존 상태에서 계산할 수 있는 값은 중복 저장하지 말고 렌더링할 때 계산합니다. 렌더링은 페이지 전체가 아니라 필요한 DOM 속성만 바꿀 수도 있습니다.
[따라하기]
아래 내용을 counter.html로 저장합니다.
```html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>상태와 렌더링</title>
</head>
<body>
<h1>수량 조절</h1>
<button id="decrease" type="button">1 줄이기</button>
<output id="count" role="status">0</output>
<button id="increase" type="button">1 늘리기</button>
<script>
let count = 0;
const countOutput = document.querySelector("#count");
const decreaseButton = document.querySelector("#decrease");
const increaseButton = document.querySelector("#increase");
function render() {
countOutput.textContent = String(count);
decreaseButton.disabled = count === 0;
}
decreaseButton.addEventListener("click", () => {
count = Math.max(0, count - 1);
render();
});
increaseButton.addEventListener("click", () => {
count += 1;
render();
});
render();
</script>
</body>
</html>
```
파일 폴더에서 macOS·Linux는 `python3 -m http.server 8000`, Windows PowerShell은 `py -m http.server 8000` 또는 `python -m http.server 8000`을 실행합니다. 브라우저에서 `http://localhost:8000/counter.html`을 열고 끝나면 Ctrl+C로 멈춥니다.
처음에는 0이고 “1 줄이기”가 비활성화됩니다. “1 늘리기”를 두 번 누르면 2, “1 줄이기”를 한 번 누르면 1이 됩니다. 이벤트 처리기는 `count`만 바꾸고 텍스트와 `disabled`는 `render()`에서 갱신합니다.
[흔한 실수]
- 이벤트 처리기마다 DOM을 따로 바꿔 상태를 여러 곳에 저장한다.
- 상태를 바꾼 뒤 `render()`를 호출하지 않는다.
- 최초 `render()`를 빼서 초기 버튼 상태가 틀린다.
- `render()` 안에서 리스너를 계속 등록해 한 클릭이 여러 번 실행된다.
[보안 주의]
일반 텍스트는 `innerHTML` 대신 `textContent`로 넣어 HTML로 해석되지 않게 합니다. URL·폼·서버 응답은 형식과 범위를 검증한 뒤 상태에 넣으세요. 브라우저 상태는 사용자가 바꿀 수 있으므로 비밀값이나 권한 판단의 근거로 믿지 않습니다. 중요한 권한 검사는 서버에서도 수행합니다. 실습은 본인 로컬 서버에서만 진행합니다.
[직접 해볼 과제]
“0으로 초기화” 버튼을 추가하세요. 최대값을 5로 정하고 5일 때 “1 늘리기”가 비활성화되도록 `render()`를 확장합니다. 상태 원본은 `count` 하나인지 확인합니다.
[확인문제]
1. 상태와 렌더링은 각각 무엇인가요?
2. 이벤트 처리기에서 상태를 바꾼 뒤 무엇을 호출해야 하나요?
3. 화면 텍스트를 상태 원본처럼 읽으면 왜 어긋나기 쉬운가요?
[다음 학습]
다음 BACK-007에서는 데이터베이스 연결과 트랜잭션으로 서버 상태를 일관되게 바꾸는 방법을 배웁니다.
[공식 참고 자료]
- WHATWG DOM 표준: https://dom.spec.whatwg.org/
- MDN textContent: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
- W3C 상태 메시지 기법: https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA22
버튼을 눌렀는데 숫자와 버튼 상태가 어긋나면 데이터와 화면의 갱신 위치가 흩어진 경우가 많습니다. 이번에는 상태를 한곳에 두고 `render()`로 화면을 갱신합니다.
[선수지식]
WEB-001의 HTML, WEB-004의 버튼 접근성, WEB-005의 DOM과 클릭 이벤트를 알고 JavaScript를 실행할 수 있어야 합니다.
[학습목표]
1. 상태와 렌더링을 쉬운 말로 설명한다.
2. 이벤트 → 상태 변경 → 렌더링 흐름을 구현한다.
3. 화면 요소를 상태 원본처럼 읽는 실수를 피한다.
[핵심개념]
상태(state)는 시간이 지나며 바뀌고 화면에 영향을 주는 데이터입니다. 로그인 여부, 수량, 선택한 탭이 예입니다. 렌더링(rendering)은 현재 상태를 DOM 속성·텍스트·스타일로 반영하는 과정입니다. DOM(Document Object Model)은 HTML 문서를 JavaScript가 다룰 수 있는 노드 트리로 표현한 모델입니다.
기본 흐름은 “사용자 이벤트 → 상태 계산 → `render()` 호출 → 화면 동기화”입니다. 상태를 단일 진실 공급원으로 관리하면 숫자와 버튼 활성 여부가 어긋날 가능성이 줄어듭니다. `render()`는 상태만 읽어 화면을 갱신하고 상태는 바꾸지 않게 나눕니다. 같은 상태로 여러 번 호출해도 같은 화면이 나오는 것이 좋습니다.
화면 텍스트를 다시 읽어 상태로 쓰면 수정 위치가 늘수록 어긋나기 쉽습니다. 기존 상태에서 계산할 수 있는 값은 중복 저장하지 말고 렌더링할 때 계산합니다. 렌더링은 페이지 전체가 아니라 필요한 DOM 속성만 바꿀 수도 있습니다.
[따라하기]
아래 내용을 counter.html로 저장합니다.
```html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>상태와 렌더링</title>
</head>
<body>
<h1>수량 조절</h1>
<button id="decrease" type="button">1 줄이기</button>
<output id="count" role="status">0</output>
<button id="increase" type="button">1 늘리기</button>
<script>
let count = 0;
const countOutput = document.querySelector("#count");
const decreaseButton = document.querySelector("#decrease");
const increaseButton = document.querySelector("#increase");
function render() {
countOutput.textContent = String(count);
decreaseButton.disabled = count === 0;
}
decreaseButton.addEventListener("click", () => {
count = Math.max(0, count - 1);
render();
});
increaseButton.addEventListener("click", () => {
count += 1;
render();
});
render();
</script>
</body>
</html>
```
파일 폴더에서 macOS·Linux는 `python3 -m http.server 8000`, Windows PowerShell은 `py -m http.server 8000` 또는 `python -m http.server 8000`을 실행합니다. 브라우저에서 `http://localhost:8000/counter.html`을 열고 끝나면 Ctrl+C로 멈춥니다.
처음에는 0이고 “1 줄이기”가 비활성화됩니다. “1 늘리기”를 두 번 누르면 2, “1 줄이기”를 한 번 누르면 1이 됩니다. 이벤트 처리기는 `count`만 바꾸고 텍스트와 `disabled`는 `render()`에서 갱신합니다.
[흔한 실수]
- 이벤트 처리기마다 DOM을 따로 바꿔 상태를 여러 곳에 저장한다.
- 상태를 바꾼 뒤 `render()`를 호출하지 않는다.
- 최초 `render()`를 빼서 초기 버튼 상태가 틀린다.
- `render()` 안에서 리스너를 계속 등록해 한 클릭이 여러 번 실행된다.
[보안 주의]
일반 텍스트는 `innerHTML` 대신 `textContent`로 넣어 HTML로 해석되지 않게 합니다. URL·폼·서버 응답은 형식과 범위를 검증한 뒤 상태에 넣으세요. 브라우저 상태는 사용자가 바꿀 수 있으므로 비밀값이나 권한 판단의 근거로 믿지 않습니다. 중요한 권한 검사는 서버에서도 수행합니다. 실습은 본인 로컬 서버에서만 진행합니다.
[직접 해볼 과제]
“0으로 초기화” 버튼을 추가하세요. 최대값을 5로 정하고 5일 때 “1 늘리기”가 비활성화되도록 `render()`를 확장합니다. 상태 원본은 `count` 하나인지 확인합니다.
[확인문제]
1. 상태와 렌더링은 각각 무엇인가요?
2. 이벤트 처리기에서 상태를 바꾼 뒤 무엇을 호출해야 하나요?
3. 화면 텍스트를 상태 원본처럼 읽으면 왜 어긋나기 쉬운가요?
[다음 학습]
다음 BACK-007에서는 데이터베이스 연결과 트랜잭션으로 서버 상태를 일관되게 바꾸는 방법을 배웁니다.
[공식 참고 자료]
- WHATWG DOM 표준: https://dom.spec.whatwg.org/
- MDN textContent: https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent
- W3C 상태 메시지 기법: https://www.w3.org/WAI/WCAG22/Techniques/aria/ARIA22
- 이전글[BACK-007][중급] 데이터베이스 연결과 트랜잭션 묶기 26.09.02
- 다음글[JSTS-007][중급] TypeScript 타입으로 실수를 먼저 찾기 26.09.02
댓글목록
등록된 댓글이 없습니다.
