{"id":21103791,"url":"https://github.com/ddooyn/react-todo-optimization","last_synced_at":"2026-04-21T20:32:19.231Z","repository":{"id":108007244,"uuid":"514732740","full_name":"ddooyn/react-todo-optimization","owner":"ddooyn","description":"리액트를 다루는 기술 10,11장 실습","archived":false,"fork":false,"pushed_at":"2022-07-17T09:15:07.000Z","size":381,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-01T23:19:53.162Z","etag":null,"topics":["react-virtualized"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ddooyn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-17T02:58:26.000Z","updated_at":"2022-07-30T13:01:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"339cdfe2-e09c-43b7-87de-34204f040537","html_url":"https://github.com/ddooyn/react-todo-optimization","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ddooyn/react-todo-optimization","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddooyn%2Freact-todo-optimization","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddooyn%2Freact-todo-optimization/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddooyn%2Freact-todo-optimization/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddooyn%2Freact-todo-optimization/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddooyn","download_url":"https://codeload.github.com/ddooyn/react-todo-optimization/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddooyn%2Freact-todo-optimization/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32108691,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T11:25:29.218Z","status":"ssl_error","status_checked_at":"2026-04-21T11:25:28.499Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react-virtualized"],"created_at":"2024-11-19T23:59:55.138Z","updated_at":"2026-04-21T20:32:19.224Z","avatar_url":"https://github.com/ddooyn.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e ## jsconfig.json 설정\n\n탭이 열려있지 않고 닫혀 있는 파일에도 import 자동 완성이 작동하게 하려면  \njsonconfig.json 파일을 생성하고 `Ctrl` + `Space` 을 누른다.  \n아래와 같이 설정이 자동 완성되어 나온다.\n\n```json\n{\n  \"compilerOptions\": {\n    \"target\": \"es2020\"\n  }\n}\n```\n\n설정을 마치고 나면 불러오려는 컴포넌트 파일이 열려 있지 않아도  \n자동 완성을 통해 컴포넌트를 불러와서 사용할 수 있다.  \n\n---\n\u003e ## 인풋, 버튼 스타일 초기화 / flex: 1\n\n```scss\ninput {\n    // 스타일 초기화\n    background: none;\n    outline: none;\n    border: none;\n    flex: 1; // 차지할 수 있는 영역 모두 차지\n    padding: 0.5rem;\n    font-size: 1.125rem;\n    line-height: 1.5;\n    color: white;\n    \u0026::placeholder {\n        color: #dee2e6;\n    }\n}\nbutton {\n    // 스타일 초기화\n    background: none;\n    outline: none;\n    border: none;\n    // ...\n}\n```\n\n---\n\u003e ## CSS `\u0026 + \u0026` 선택자\n```scss\n// 엘리먼트 사이사이에 테두리를 넣어 줌\n\u0026 + \u0026 {\n  border-top: 1px solid #dee2e6;\n}\n```\n\n---\n\u003e ## classnames 라이브러리\n`cn('default클래스이름', 조건부클래스이름)` 형태  \nchecked true일 때만 기존 checkbox 클래스 + checked 클래스가 붙음\n```jsx\nimport cn from 'classnames';\n// ...\nconst TodoListItem = ({ todo }) =\u003e {\n  const { text, checked } = todo;\n  return (\n    \u003cdiv className=\"TodoListItem\"\u003e\n      \u003cdiv className={cn('checkbox', { checked })}\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n};\n// ...\n```\n스타일링은 이렇게!\n```css\n.checkbox {\n  display: flex;\n  align-items: center;\n  flex: 1;\n  cursor: pointer;\n  svg {\n    font-size: 1.5rem;\n  }\n  .text {\n    flex: 1;\n    margin-left: 0.5rem;\n  }\n  /* checked 클래스가 있을 때 */\n  \u0026.checked {\n    svg {\n      color: #22b8cf;\n    }\n    .text {\n      color: #adb5bd;\n      text-decoration: line-through;\n    }\n  }\n}\n```\n\n---\n\u003e ## useCallback(() =\u003e {}, [])\n컴포넌트가 리렌더링될 때마다 함수를 새로 만드는 것이 아니라,   \n한번 함수를 만든 뒤 재사용할 수 있도록 `useCallback` Hook 이용\n```jsx\nconst TodoInsert = () =\u003e {\n  const [value, setValue] = useState('');\n\n  const onChange = useCallback((e) =\u003e {\n    setValue(e.target.value);\n  }, []);\n  // ...\n}\n```\n\n---\n\u003e ## useReducer\nuseReducer를 사용하는 방법은 기존 코드를 많이 고쳐야 한다는 단점이 있지만,\n상태를 업데이트하는 로직으로 모아 컴포넌트 바깥에 둘 수 있다는 장점이 있다.\n```jsx\nfunction todoReducer(todos, action) {\n  switch (action.type) {\n    case 'INSERT':\n      return todos.concat(action.todo);\n    case 'REMOVE':\n      return todos.filter((todo) =\u003e todo.id !== action.id);\n    case 'TOGGLE':\n      return todos.map((todo) =\u003e\n        todo.id === action.id ? { ...todo, checked: !todo.checked } : todo,\n      );\n    default:\n      return todos;\n  }\n}\n\nconst App = () =\u003e {\n  // const [todos, setTodos] = useState(createBulkTodos);\n  const [todos, dispatch] = useReducer(todoReducer, undefined, createBulkTodos);\n\n  const nextId = useRef(2501);\n  const onInsert = useCallback((text) =\u003e {\n    const todo = {\n      id: nextId.current,\n      text,\n      checked: false,\n    };\n    // setTodos((todos) =\u003e todos.concat(todo));\n    dispatch({ type: 'INSERT', todo });\n    nextId.current += 1;\n  }, []);\n\n  const onRemove = useCallback((id) =\u003e {\n    // setTodos((todos) =\u003e todos.filter((todo) =\u003e todo.id !== id));\n    dispatch({ type: 'REMOVE', id });\n  }, []);\n\n  const onToggle = useCallback((id) =\u003e {\n    // setTodos((todos) =\u003e\n    //   todos.map((todo) =\u003e\n    //     todo.id === id ? { ...todo, checked: !todo.checked } : todo,\n    //   ),\n    // );\n    dispatch({ type: 'TOGGLE', id });\n  }, []);\n\n  return (\n    //...\n  );\n};\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddooyn%2Freact-todo-optimization","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddooyn%2Freact-todo-optimization","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddooyn%2Freact-todo-optimization/lists"}