먼저 볼 장면
멋진 3D 지도만 복제하고 계산 서버를 놓치기
이 저장소는 통합 프런트엔드입니다. 실시간 CityIO 백엔드와 도시별 데이터·모듈이 없으면 같은 결과가 나오지 않으므로 화면과 계산 책임을 나눠 봅니다.
URL 선택, WebSocket 메시지, Redux 상태, 지도 렌더링을 따라가며 참여형 도시 시뮬레이션의 구성요소를 배웁니다.
블록 하나를 주거에서 공원으로 바꾸면, 어떤 데이터와 가정이 결과 화면까지 이동할까요?
GPL-3.0 CityScopeJS의 핵심 데이터 흐름만 읽습니다. 기존 코드를 배포하는 과제가 아니라 접근성·비용·공정성 지표를 학생이 새로 정의하는 설계 과정입니다.
CityScope 연구 개념은 살아 있지만 이 프런트엔드의 최신 릴리스는 2022년이고 기본 브랜치 마지막 의미 있는 코드는 2024년입니다. 전체 복제 대신 데이터 흐름을 읽고 작은 독립 시뮬레이터를 설계합니다.
이 저장소는 통합 프런트엔드입니다. 실시간 CityIO 백엔드와 도시별 데이터·모듈이 없으면 같은 결과가 나오지 않으므로 화면과 계산 책임을 나눠 봅니다.
관심 분야의 문제를 정하고, 코드와 데이터를 읽고, AI 실험을 검증한 뒤 결과를 발표합니다.
URL 쿼리를 읽어 CityScope 편집기와 CityIO 목록 화면 중 하나를 고르는 작은 라우터를 봅니다.
주소에 `cityscope` 키가 있으면 그 값을 테이블 이름으로 전달하고, 없으면 일반 CityIO 화면을 엽니다.
`?cityscope=seoul-school-zone` 같은 주소 세 개와 각 주소가 열 화면을 표로 만듭니다.
URL→도시 테이블→화면 선택 흐름도
1cb2e63 const keys = Object.keys(parsed);
if (keys.includes("cityscope")) {
selectView("cityscopejs", parsed.cityscope);
} else {
setViewSelectorState("cityio");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);해석한 URL에서 모든 키 이름을 꺼냅니다.
`cityscope` 키가 있으면 그 값으로 편집기 화면을 선택합니다.
없으면 CityIO 목록 화면을 기본으로 선택합니다.
주소에 `?cityscope=gangnam`이 있지만 목록 화면만 열립니다.
먼저 한 가지를 골라 보세요.
WebSocket 연결이 열리면 테이블 이름을 담은 `LISTEN` 메시지를 보내는 흐름을 읽습니다.
연결은 공유되고 끊기면 재연결을 시도합니다. 열린 뒤에만 테이블 구독 메시지를 보내야 합니다.
연결 전·열림·메시지 수신·재연결 네 상태에서 사용자에게 보여 줄 문구를 씁니다.
연결 상태별 오류·복구 카드
1cb2e63 const { sendJsonMessage, lastJsonMessage, readyState } = useWebSocket(
cityIOSettings.cityIO.websocketURL,
{
share: true,
shouldReconnect: () => true,
},
)
// When the WS connection state (readyState) changes to OPEN,훅은 메시지 보내기, 마지막 메시지, 연결 상태를 돌려줍니다.
서버 주소는 공통 설정에서 읽습니다.
연결을 구성요소끼리 공유하고 끊기면 다시 연결하도록 설정합니다.
브라우저가 오프라인이 됐다가 돌아왔지만 지도가 이전 값에 멈췄습니다.
먼저 한 가지를 골라 보세요.
Redux slice가 도시 데이터, 로딩 완료 여부, 테이블 이름을 갱신하는 작은 책임을 봅니다.
세 reducer는 각자 하나의 상태 필드만 바꿉니다. 메시지는 도착했는데 화면이 안 바뀌면 dispatch와 이 저장소 사이를 추적합니다.
`TABLE_SNAPSHOT`을 받았을 때 바뀌어야 할 세 상태와 이를 읽는 화면을 연결합니다.
메시지→Redux 상태→화면 의존성 지도
1cb2e63 reducers: {
updateCityIOdata: (state, action) => {
state.cityIOdata = action.payload;
},
toggleCityIOisDone: (state, action) => {
state.cityIOisDone = action.payload;
},
updateCityIOtableName: (state, action) => {
state.cityIOtableName = action.payload;
},
},`updateCityIOdata`는 메시지의 도시 내용을 저장합니다.
완료 토글은 화면을 그릴 준비가 됐는지 저장합니다.
세 번째 규칙은 현재 연결할 도시 테이블 이름을 보관합니다.
WebSocket 로그에는 새 데이터가 보이지만 차트가 바뀌지 않습니다.
먼저 한 가지를 골라 보세요.
데이터 준비 여부에 따라 CityIO 연결, 지도, 메뉴, 차트를 조건부로 여는 화면 구조를 읽습니다.
프런트엔드는 테이블이 있으면 데이터를 구독하고, 완료 플래그가 참일 때만 시각 요소를 엽니다. 도시 지표 계산 자체는 다른 서비스와 모듈에 있습니다.
원본 전체 대신 학교 주변 보행 접근성 한 지표만 계산하는 입력·규칙·출력 프로토타입을 정합니다.
단일 도시 질문용 독립 시뮬레이터 명세
1cb2e63 {/* if we got a cityIO table name, start cityIO module */}
{tableName && <CityIO tableName={tableName} />}
{/* if cityIO module is done loading, start the CSjs app */}
{cityIOisDone && (
<>
<div style={{ height: '100vh', width: '100vw', position: 'relative', overflow: 'hidden' }}>
<DeckGLMap />
</div>
<MenuContainer />
<VisContainer />테이블 이름이 있을 때만 CityIO 연결 구성요소를 시작합니다.
데이터 로딩 완료 플래그가 참일 때만 앱 시각 요소를 엽니다.
지도, 메뉴, 지표 차트가 서로 다른 구성요소로 나뉩니다.
지도 UI는 복제했지만 어떤 시나리오를 선택해도 지표가 없습니다.
먼저 한 가지를 골라 보세요.
이번 코스의 결과물
도시 시뮬레이터의 숫자가 정책 참여를 돕는 순간과 오히려 선택을 숨기는 순간은 언제인가요?
다음 코스