{"action":"created","comment":{"url":"https://api.github.com/repos/reactkr/react/pulls/comments/26075207","id":26075207,"diff_hunk":"@@ -0,0 +1,132 @@\n+---\n+id: reconciliation-ko-KR\n+title: 비교조정(Reconciliation)\n+permalink: reconciliation-ko-KR.html\n+prev: special-non-dom-attributes-ko-KR.html\n+next: glossary-ko-KR.html\n+---\n+\n+React의 주요 설계 철학은 업데이트할 때마다 전체 앱을 다시 렌더하는 것처럼 보이게 API를 만드는 것입니다. 이렇게 하면 애플리케이션 작성이 훨씬 쉬워지지만 한편으로는 이를 가능하게 하는 것은 또한 엄청난 도전 과제이기도 합니다. 이 글에서는 어떻게 강력한 휴리스틱으로 O(n<sup>3</sup>) 복잡도의 문제를 O(n)짜리로 옮겨낼 수 있었는지 설명합니다.\n+\n+\n+## 동기\n+\n+최소한의 연산으로 어떤 트리를 다른 트리로 바꾸는 것은 복잡하고 많이 연구된 문제입니다. n을 트리에 있는 노드 수라고 할 때 [최신 알고리즘](http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf)은 O(n<sup>3</sup>) 복잡도를 가집니다.\n+\n+다시 말해 1000개의 노드를 표시하려면 10억 번 수준의 비교를 해야 한다는 뜻입니다. 이는 우리가 필요한 용도로는 너무 비쌉니다. 이 숫자를 좀 더 가시적으로 표현해 봅시다. 요즘 CPU는 1초에 대략 30억 번의 연산을 합니다. 따라서 아무리 가장 빠른 구현으로도 1초 안에 이러한 비교는 계산해낼 수 없습니다.\n+\n+최적의 알고리즘을 사용할 수 없기 때문에 다음의 두 가지 가정에 기반한 휴리스틱을 사용한 O(n) 알고리즘으로 구현했습니다.\n+\n+1. 같은 클래스의 두 컴포넌트는 비슷한 트리를 생성하고, 서로 다른 클래스를 가진 두 컴포넌트는 서로 다른 트리를 생성할 것이다.\n+2. 각 렌더 과정들 사이에 유지되는 엘리먼트에 고유한 키를 제공할 수 있다.\n+\n+실제로 이러한 가정은 거의 모든 실용적인 상황에서 굉장히 빠릅니다.\n+\n+\n+## 일대일 비교\n+\n+트리 비교를 하기 위해서는 먼저 두 노드를 비교할 수 있어야 합니다. 세 가지 경우를 다룹니다.\n+\n+\n+### 서로 다른 노드 타입\n+\n+두 노드의 타입이 서로 다르다면, React는 이를 두 개의 서로 다른 서브트리로 간주해 처음 것을 버리고 두번째 것을 만들어 삽입합니다.\n+\n+```xml\n+renderA: <div />\n+renderB: <span />\n+=> [removeNode <div />], [insertNode <span />]\n+```\n+\n+동일한 로직이 커스텀 컴포넌트에 대해서도 적용됩니다. 타입이 다르다면 React는 그 컴포넌트들이 무엇을 렌더하는지 조차도 비교하지 않습니다. 그저 처음 것을 DOM에서 제거하고 두번째 것을 삽입합니다.\n+\n+```xml\n+renderA: <Header />\n+renderB: <Content />\n+=> [removeNode <Header />], [insertNode <Content />]\n+```\n+\n+이러한 고수준의 사실을 알 수 있다는 것이 React의 비교 알고리즘이 빠르면서 정확할 수 있는 비결입니다. 트리의 커다란 부분을 일찌감치 탐색 대상에서 제외하고 비슷할 가능성이 높은 부분에 집중할 수 있는 좋은 휴리스틱을 제공합니다.\n+\n+`<Header>` 엘리먼트가 생성하는 DOM이 `<Content>`가 생성하는 것과 비슷하게 생길 확률은 매우 낮습니다. 이 두 구조를 비교하는데 시간을 낭비하지 않고 React는 그냥 트리를 처음부터 새로 만듭니다.\n+\n+한편 두 번의 연속적인 렌더에서 같은 위치에 `<Header>` 엘리먼트가 있다면 비슷한 구조일 것이므로 탐색할만 합니다.\n+\n+\n+### DOM 노드\n+\n+두 DOM 노드를 비교할 때는 어트리뷰트를 보고 무엇이 바뀌었는지 선형 시간 안에 결정할 수 있습니다.\n+\n+```xml\n+renderA: <div id=\"before\" />\n+renderB: <div id=\"after\" />\n+=> [replaceAttribute id \"after\"]\n+```\n+\n+스타일을 불명확한 문자열로 다루지 않고 키-값 객체를 사용합니다. 이는 변경된 프로퍼티만 업데이트 하도록 해줍니다.\n+\n+```xml\n+renderA: <div style={{'{{'}}color: 'red'}} />\n+renderB: <div style={{'{{'}}fontWeight: 'bold'}} />\n+=> [removeStyle color], [addStyle font-weight 'bold']\n+```\n+\n+어트리뷰트가 업데이트된 다음에는, 모든 자식에 대해 재귀적으로 같은 절차를 진행합니다.\n+\n+\n+### 커스텀 컴포넌트\n+\n+우리는 두 커스텀 컴포넌트를 같은 것으로 취급하기로 했습니다. 컴포넌트는 상태를 가지기 때문에 새 컴포넌트를 그냥 사용할 수는 없습니다. React는 새 컴포넌트의 모든 어트리뷰트를 취해 이전 컴포넌트의 `component[Will/Did]ReceiveProps()`를 호출해 줍니다.\n+\n+이제 이전 컴포넌트가 작동합니다. 거기 있는 `render()` 메소드가 호출되고 비교 알고리즘이 다시 새로운 결과와 이전 결과를 비교합니다.\n+\n+\n+## 목록끼리 비교\n+\n+### 문제가 되는 경우\n+\n+자식 비교조정(children reconciliation)을 하기 위해 React는 매우 단순한 방식을 사용합니다. 자식 목록을 서로 비교해가다가 차이를 발견하면 변경 사항을 적용합니다.","path":"docs/docs/ref-08-reconciliation.ko-KR.md","position":88,"original_position":88,"commit_id":"226bab0578ca38085ae81bbf9311f0a0e0cef571","original_commit_id":"226bab0578ca38085ae81bbf9311f0a0e0cef571","user":{"login":"marocchino","id":128431,"avatar_url":"https://avatars.githubusercontent.com/u/128431?v=3","gravatar_id":"","url":"https://api.github.com/users/marocchino","html_url":"https://github.com/marocchino","followers_url":"https://api.github.com/users/marocchino/followers","following_url":"https://api.github.com/users/marocchino/following{/other_user}","gists_url":"https://api.github.com/users/marocchino/gists{/gist_id}","starred_url":"https://api.github.com/users/marocchino/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/marocchino/subscriptions","organizations_url":"https://api.github.com/users/marocchino/orgs","repos_url":"https://api.github.com/users/marocchino/repos","events_url":"https://api.github.com/users/marocchino/events{/privacy}","received_events_url":"https://api.github.com/users/marocchino/received_events","type":"User","site_admin":false},"body":"> 자식 비교조정(children reconciliation)을 하기 위해 React는 매우 단순한 방식을 사용합니다.\r\n> React는 매우 단순하게 자식을 비교조정(children reconciliation)합니다.","created_at":"2015-03-09T20:57:26Z","updated_at":"2015-03-09T20:57:26Z","html_url":"https://github.com/reactkr/react/pull/44#discussion_r26075207","pull_request_url":"https://api.github.com/repos/reactkr/react/pulls/44","_links":{"self":{"href":"https://api.github.com/repos/reactkr/react/pulls/comments/26075207"},"html":{"href":"https://github.com/reactkr/react/pull/44#discussion_r26075207"},"pull_request":{"href":"https://api.github.com/repos/reactkr/react/pulls/44"}}},"pull_request":{"url":"https://api.github.com/repos/reactkr/react/pulls/44","id":30757525,"html_url":"https://github.com/reactkr/react/pull/44","diff_url":"https://github.com/reactkr/react/pull/44.diff","patch_url":"https://github.com/reactkr/react/pull/44.patch","issue_url":"https://api.github.com/repos/reactkr/react/issues/44","number":44,"state":"open","locked":false,"title":"ref-08-reconciliation","user":{"login":"dittos","id":2622,"avatar_url":"https://avatars.githubusercontent.com/u/2622?v=3","gravatar_id":"","url":"https://api.github.com/users/dittos","html_url":"https://github.com/dittos","followers_url":"https://api.github.com/users/dittos/followers","following_url":"https://api.github.com/users/dittos/following{/other_user}","gists_url":"https://api.github.com/users/dittos/gists{/gist_id}","starred_url":"https://api.github.com/users/dittos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dittos/subscriptions","organizations_url":"https://api.github.com/users/dittos/orgs","repos_url":"https://api.github.com/users/dittos/repos","events_url":"https://api.github.com/users/dittos/events{/privacy}","received_events_url":"https://api.github.com/users/dittos/received_events","type":"User","site_admin":false},"body":"늦어서 죄송합니다 :crying_cat_face: \r\n\r\nbased on 941cba679e7b1ca909f12af908f6aebc457fbc11","created_at":"2015-03-09T12:50:50Z","updated_at":"2015-03-09T20:57:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"71e34bc930855bf5217831fd8cec130d50d54597","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/reactkr/react/pulls/44/commits","review_comments_url":"https://api.github.com/repos/reactkr/react/pulls/44/comments","review_comment_url":"https://api.github.com/repos/reactkr/react/pulls/comments{/number}","comments_url":"https://api.github.com/repos/reactkr/react/issues/44/comments","statuses_url":"https://api.github.com/repos/reactkr/react/statuses/226bab0578ca38085ae81bbf9311f0a0e0cef571","head":{"label":"reactkr:dittos/trans-ref-08","ref":"dittos/trans-ref-08","sha":"226bab0578ca38085ae81bbf9311f0a0e0cef571","user":{"login":"reactkr","id":9114161,"avatar_url":"https://avatars.githubusercontent.com/u/9114161?v=3","gravatar_id":"","url":"https://api.github.com/users/reactkr","html_url":"https://github.com/reactkr","followers_url":"https://api.github.com/users/reactkr/followers","following_url":"https://api.github.com/users/reactkr/following{/other_user}","gists_url":"https://api.github.com/users/reactkr/gists{/gist_id}","starred_url":"https://api.github.com/users/reactkr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactkr/subscriptions","organizations_url":"https://api.github.com/users/reactkr/orgs","repos_url":"https://api.github.com/users/reactkr/repos","events_url":"https://api.github.com/users/reactkr/events{/privacy}","received_events_url":"https://api.github.com/users/reactkr/received_events","type":"Organization","site_admin":false},"repo":{"id":29853751,"name":"react","full_name":"reactkr/react","owner":{"login":"reactkr","id":9114161,"avatar_url":"https://avatars.githubusercontent.com/u/9114161?v=3","gravatar_id":"","url":"https://api.github.com/users/reactkr","html_url":"https://github.com/reactkr","followers_url":"https://api.github.com/users/reactkr/followers","following_url":"https://api.github.com/users/reactkr/following{/other_user}","gists_url":"https://api.github.com/users/reactkr/gists{/gist_id}","starred_url":"https://api.github.com/users/reactkr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactkr/subscriptions","organizations_url":"https://api.github.com/users/reactkr/orgs","repos_url":"https://api.github.com/users/reactkr/repos","events_url":"https://api.github.com/users/reactkr/events{/privacy}","received_events_url":"https://api.github.com/users/reactkr/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/reactkr/react","description":"A declarative, efficient, and flexible JavaScript library for building user interfaces.","fork":true,"url":"https://api.github.com/repos/reactkr/react","forks_url":"https://api.github.com/repos/reactkr/react/forks","keys_url":"https://api.github.com/repos/reactkr/react/keys{/key_id}","collaborators_url":"https://api.github.com/repos/reactkr/react/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/reactkr/react/teams","hooks_url":"https://api.github.com/repos/reactkr/react/hooks","issue_events_url":"https://api.github.com/repos/reactkr/react/issues/events{/number}","events_url":"https://api.github.com/repos/reactkr/react/events","assignees_url":"https://api.github.com/repos/reactkr/react/assignees{/user}","branches_url":"https://api.github.com/repos/reactkr/react/branches{/branch}","tags_url":"https://api.github.com/repos/reactkr/react/tags","blobs_url":"https://api.github.com/repos/reactkr/react/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/reactkr/react/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/reactkr/react/git/refs{/sha}","trees_url":"https://api.github.com/repos/reactkr/react/git/trees{/sha}","statuses_url":"https://api.github.com/repos/reactkr/react/statuses/{sha}","languages_url":"https://api.github.com/repos/reactkr/react/languages","stargazers_url":"https://api.github.com/repos/reactkr/react/stargazers","contributors_url":"https://api.github.com/repos/reactkr/react/contributors","subscribers_url":"https://api.github.com/repos/reactkr/react/subscribers","subscription_url":"https://api.github.com/repos/reactkr/react/subscription","commits_url":"https://api.github.com/repos/reactkr/react/commits{/sha}","git_commits_url":"https://api.github.com/repos/reactkr/react/git/commits{/sha}","comments_url":"https://api.github.com/repos/reactkr/react/comments{/number}","issue_comment_url":"https://api.github.com/repos/reactkr/react/issues/comments{/number}","contents_url":"https://api.github.com/repos/reactkr/react/contents/{+path}","compare_url":"https://api.github.com/repos/reactkr/react/compare/{base}...{head}","merges_url":"https://api.github.com/repos/reactkr/react/merges","archive_url":"https://api.github.com/repos/reactkr/react/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/reactkr/react/downloads","issues_url":"https://api.github.com/repos/reactkr/react/issues{/number}","pulls_url":"https://api.github.com/repos/reactkr/react/pulls{/number}","milestones_url":"https://api.github.com/repos/reactkr/react/milestones{/number}","notifications_url":"https://api.github.com/repos/reactkr/react/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/reactkr/react/labels{/name}","releases_url":"https://api.github.com/repos/reactkr/react/releases{/id}","created_at":"2015-01-26T09:19:42Z","updated_at":"2015-03-09T12:24:56Z","pushed_at":"2015-03-09T15:08:15Z","git_url":"git://github.com/reactkr/react.git","ssh_url":"git@github.com:reactkr/react.git","clone_url":"https://github.com/reactkr/react.git","svn_url":"https://github.com/reactkr/react","homepage":"http://facebook.github.io/react/","size":47752,"stargazers_count":3,"watchers_count":3,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":2,"forks":3,"open_issues":2,"watchers":3,"default_branch":"translation"}},"base":{"label":"reactkr:translation","ref":"translation","sha":"a01167a97859b65b3419db3a271553aa0b6f43b4","user":{"login":"reactkr","id":9114161,"avatar_url":"https://avatars.githubusercontent.com/u/9114161?v=3","gravatar_id":"","url":"https://api.github.com/users/reactkr","html_url":"https://github.com/reactkr","followers_url":"https://api.github.com/users/reactkr/followers","following_url":"https://api.github.com/users/reactkr/following{/other_user}","gists_url":"https://api.github.com/users/reactkr/gists{/gist_id}","starred_url":"https://api.github.com/users/reactkr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactkr/subscriptions","organizations_url":"https://api.github.com/users/reactkr/orgs","repos_url":"https://api.github.com/users/reactkr/repos","events_url":"https://api.github.com/users/reactkr/events{/privacy}","received_events_url":"https://api.github.com/users/reactkr/received_events","type":"Organization","site_admin":false},"repo":{"id":29853751,"name":"react","full_name":"reactkr/react","owner":{"login":"reactkr","id":9114161,"avatar_url":"https://avatars.githubusercontent.com/u/9114161?v=3","gravatar_id":"","url":"https://api.github.com/users/reactkr","html_url":"https://github.com/reactkr","followers_url":"https://api.github.com/users/reactkr/followers","following_url":"https://api.github.com/users/reactkr/following{/other_user}","gists_url":"https://api.github.com/users/reactkr/gists{/gist_id}","starred_url":"https://api.github.com/users/reactkr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/reactkr/subscriptions","organizations_url":"https://api.github.com/users/reactkr/orgs","repos_url":"https://api.github.com/users/reactkr/repos","events_url":"https://api.github.com/users/reactkr/events{/privacy}","received_events_url":"https://api.github.com/users/reactkr/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/reactkr/react","description":"A declarative, efficient, and flexible JavaScript library for building user interfaces.","fork":true,"url":"https://api.github.com/repos/reactkr/react","forks_url":"https://api.github.com/repos/reactkr/react/forks","keys_url":"https://api.github.com/repos/reactkr/react/keys{/key_id}","collaborators_url":"https://api.github.com/repos/reactkr/react/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/reactkr/react/teams","hooks_url":"https://api.github.com/repos/reactkr/react/hooks","issue_events_url":"https://api.github.com/repos/reactkr/react/issues/events{/number}","events_url":"https://api.github.com/repos/reactkr/react/events","assignees_url":"https://api.github.com/repos/reactkr/react/assignees{/user}","branches_url":"https://api.github.com/repos/reactkr/react/branches{/branch}","tags_url":"https://api.github.com/repos/reactkr/react/tags","blobs_url":"https://api.github.com/repos/reactkr/react/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/reactkr/react/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/reactkr/react/git/refs{/sha}","trees_url":"https://api.github.com/repos/reactkr/react/git/trees{/sha}","statuses_url":"https://api.github.com/repos/reactkr/react/statuses/{sha}","languages_url":"https://api.github.com/repos/reactkr/react/languages","stargazers_url":"https://api.github.com/repos/reactkr/react/stargazers","contributors_url":"https://api.github.com/repos/reactkr/react/contributors","subscribers_url":"https://api.github.com/repos/reactkr/react/subscribers","subscription_url":"https://api.github.com/repos/reactkr/react/subscription","commits_url":"https://api.github.com/repos/reactkr/react/commits{/sha}","git_commits_url":"https://api.github.com/repos/reactkr/react/git/commits{/sha}","comments_url":"https://api.github.com/repos/reactkr/react/comments{/number}","issue_comment_url":"https://api.github.com/repos/reactkr/react/issues/comments{/number}","contents_url":"https://api.github.com/repos/reactkr/react/contents/{+path}","compare_url":"https://api.github.com/repos/reactkr/react/compare/{base}...{head}","merges_url":"https://api.github.com/repos/reactkr/react/merges","archive_url":"https://api.github.com/repos/reactkr/react/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/reactkr/react/downloads","issues_url":"https://api.github.com/repos/reactkr/react/issues{/number}","pulls_url":"https://api.github.com/repos/reactkr/react/pulls{/number}","milestones_url":"https://api.github.com/repos/reactkr/react/milestones{/number}","notifications_url":"https://api.github.com/repos/reactkr/react/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/reactkr/react/labels{/name}","releases_url":"https://api.github.com/repos/reactkr/react/releases{/id}","created_at":"2015-01-26T09:19:42Z","updated_at":"2015-03-09T12:24:56Z","pushed_at":"2015-03-09T15:08:15Z","git_url":"git://github.com/reactkr/react.git","ssh_url":"git@github.com:reactkr/react.git","clone_url":"https://github.com/reactkr/react.git","svn_url":"https://github.com/reactkr/react","homepage":"http://facebook.github.io/react/","size":47752,"stargazers_count":3,"watchers_count":3,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"open_issues_count":2,"forks":3,"open_issues":2,"watchers":3,"default_branch":"translation"}},"_links":{"self":{"href":"https://api.github.com/repos/reactkr/react/pulls/44"},"html":{"href":"https://github.com/reactkr/react/pull/44"},"issue":{"href":"https://api.github.com/repos/reactkr/react/issues/44"},"comments":{"href":"https://api.github.com/repos/reactkr/react/issues/44/comments"},"review_comments":{"href":"https://api.github.com/repos/reactkr/react/pulls/44/comments"},"review_comment":{"href":"https://api.github.com/repos/reactkr/react/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/reactkr/react/pulls/44/commits"},"statuses":{"href":"https://api.github.com/repos/reactkr/react/statuses/226bab0578ca38085ae81bbf9311f0a0e0cef571"}}}}