From 3f08a753b3739af9c295a4484c174cbb791e95b0 Mon Sep 17 00:00:00 2001 From: Eungjin Kim <44359045+yesjin-git@users.noreply.github.com> Date: Sun, 24 Mar 2019 16:45:24 +0900 Subject: [PATCH 1/4] first draft: thinking in react --- content/docs/thinking-in-react.md | 294 +++++++++++++++--------------- 1 file changed, 146 insertions(+), 148 deletions(-) diff --git a/content/docs/thinking-in-react.md b/content/docs/thinking-in-react.md index 7b2e2e7e6..fd3171e4f 100644 --- a/content/docs/thinking-in-react.md +++ b/content/docs/thinking-in-react.md @@ -1,148 +1,146 @@ ---- -id: thinking-in-react -title: Thinking in React -permalink: docs/thinking-in-react.html -redirect_from: - - 'blog/2013/11/05/thinking-in-react.html' - - 'docs/thinking-in-react-zh-CN.html' -prev: composition-vs-inheritance.html ---- - -React is, in our opinion, the premier way to build big, fast Web apps with JavaScript. It has scaled very well for us at Facebook and Instagram. - -One of the many great parts of React is how it makes you think about apps as you build them. In this document, we'll walk you through the thought process of building a searchable product data table using React. - -## Start With A Mock {#start-with-a-mock} - -Imagine that we already have a JSON API and a mock from our designer. The mock looks like this: - -![Mockup](../images/blog/thinking-in-react-mock.png) - -Our JSON API returns some data that looks like this: - -``` -[ - {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, - {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, - {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, - {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, - {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, - {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} -]; -``` - -## Step 1: Break The UI Into A Component Hierarchy {#step-1-break-the-ui-into-a-component-hierarchy} - -The first thing you'll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names. If you're working with a designer, they may have already done this, so go talk to them! Their Photoshop layer names may end up being the names of your React components! - -But how do you know what should be its own component? Just use the same techniques for deciding if you should create a new function or object. One such technique is the [single responsibility principle](https://en.wikipedia.org/wiki/Single_responsibility_principle), that is, a component should ideally only do one thing. If it ends up growing, it should be decomposed into smaller subcomponents. - -Since you're often displaying a JSON data model to a user, you'll find that if your model was built correctly, your UI (and therefore your component structure) will map nicely. That's because UI and data models tend to adhere to the same *information architecture*, which means the work of separating your UI into components is often trivial. Just break it up into components that represent exactly one piece of your data model. - -![Component diagram](../images/blog/thinking-in-react-components.png) - -You'll see here that we have five components in our simple app. We've italicized the data each component represents. - - 1. **`FilterableProductTable` (orange):** contains the entirety of the example - 2. **`SearchBar` (blue):** receives all *user input* - 3. **`ProductTable` (green):** displays and filters the *data collection* based on *user input* - 4. **`ProductCategoryRow` (turquoise):** displays a heading for each *category* - 5. **`ProductRow` (red):** displays a row for each *product* - -If you look at `ProductTable`, you'll see that the table header (containing the "Name" and "Price" labels) isn't its own component. This is a matter of preference, and there's an argument to be made either way. For this example, we left it as part of `ProductTable` because it is part of rendering the *data collection* which is `ProductTable`'s responsibility. However, if this header grows to be complex (i.e. if we were to add affordances for sorting), it would certainly make sense to make this its own `ProductTableHeader` component. - -Now that we've identified the components in our mock, let's arrange them into a hierarchy. This is easy. Components that appear within another component in the mock should appear as a child in the hierarchy: - - * `FilterableProductTable` - * `SearchBar` - * `ProductTable` - * `ProductCategoryRow` - * `ProductRow` - -## Step 2: Build A Static Version in React {#step-2-build-a-static-version-in-react} - -

See the Pen Thinking In React: Step 2 on CodePen.

- - -Now that you have your component hierarchy, it's time to implement your app. The easiest way is to build a version that takes your data model and renders the UI but has no interactivity. It's best to decouple these processes because building a static version requires a lot of typing and no thinking, and adding interactivity requires a lot of thinking and not a lot of typing. We'll see why. - -To build a static version of your app that renders your data model, you'll want to build components that reuse other components and pass data using *props*. *props* are a way of passing data from parent to child. If you're familiar with the concept of *state*, **don't use state at all** to build this static version. State is reserved only for interactivity, that is, data that changes over time. Since this is a static version of the app, you don't need it. - -You can build top-down or bottom-up. That is, you can either start with building the components higher up in the hierarchy (i.e. starting with `FilterableProductTable`) or with the ones lower in it (`ProductRow`). In simpler examples, it's usually easier to go top-down, and on larger projects, it's easier to go bottom-up and write tests as you build. - -At the end of this step, you'll have a library of reusable components that render your data model. The components will only have `render()` methods since this is a static version of your app. The component at the top of the hierarchy (`FilterableProductTable`) will take your data model as a prop. If you make a change to your underlying data model and call `ReactDOM.render()` again, the UI will be updated. It's easy to see how your UI is updated and where to make changes since there's nothing complicated going on. React's **one-way data flow** (also called *one-way binding*) keeps everything modular and fast. - -Simply refer to the [React docs](/docs/) if you need help executing this step. - -### A Brief Interlude: Props vs State {#a-brief-interlude-props-vs-state} - -There are two types of "model" data in React: props and state. It's important to understand the distinction between the two; skim [the official React docs](/docs/interactivity-and-dynamic-uis.html) if you aren't sure what the difference is. - -## Step 3: Identify The Minimal (but complete) Representation Of UI State {#step-3-identify-the-minimal-but-complete-representation-of-ui-state} - -To make your UI interactive, you need to be able to trigger changes to your underlying data model. React makes this easy with **state**. - -To build your app correctly, you first need to think of the minimal set of mutable state that your app needs. The key here is [DRY: *Don't Repeat Yourself*](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). Figure out the absolute minimal representation of the state your application needs and compute everything else you need on-demand. For example, if you're building a TODO list, just keep an array of the TODO items around; don't keep a separate state variable for the count. Instead, when you want to render the TODO count, simply take the length of the TODO items array. - -Think of all of the pieces of data in our example application. We have: - - * The original list of products - * The search text the user has entered - * The value of the checkbox - * The filtered list of products - -Let's go through each one and figure out which one is state. Simply ask three questions about each piece of data: - - 1. Is it passed in from a parent via props? If so, it probably isn't state. - 2. Does it remain unchanged over time? If so, it probably isn't state. - 3. Can you compute it based on any other state or props in your component? If so, it isn't state. - -The original list of products is passed in as props, so that's not state. The search text and the checkbox seem to be state since they change over time and can't be computed from anything. And finally, the filtered list of products isn't state because it can be computed by combining the original list of products with the search text and value of the checkbox. - -So finally, our state is: - - * The search text the user has entered - * The value of the checkbox - -## Step 4: Identify Where Your State Should Live {#step-4-identify-where-your-state-should-live} - -

See the Pen Thinking In React: Step 4 on CodePen.

- -OK, so we've identified what the minimal set of app state is. Next, we need to identify which component mutates, or *owns*, this state. - -Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. **This is often the most challenging part for newcomers to understand,** so follow these steps to figure it out: - -For each piece of state in your application: - - * Identify every component that renders something based on that state. - * Find a common owner component (a single component above all the components that need the state in the hierarchy). - * Either the common owner or another component higher up in the hierarchy should own the state. - * If you can't find a component where it makes sense to own the state, create a new component simply for holding the state and add it somewhere in the hierarchy above the common owner component. - -Let's run through this strategy for our application: - - * `ProductTable` needs to filter the product list based on state and `SearchBar` needs to display the search text and checked state. - * The common owner component is `FilterableProductTable`. - * It conceptually makes sense for the filter text and checked value to live in `FilterableProductTable` - -Cool, so we've decided that our state lives in `FilterableProductTable`. First, add an instance property `this.state = {filterText: '', inStockOnly: false}` to `FilterableProductTable`'s `constructor` to reflect the initial state of your application. Then, pass `filterText` and `inStockOnly` to `ProductTable` and `SearchBar` as a prop. Finally, use these props to filter the rows in `ProductTable` and set the values of the form fields in `SearchBar`. - -You can start seeing how your application will behave: set `filterText` to `"ball"` and refresh your app. You'll see that the data table is updated correctly. - -## Step 5: Add Inverse Data Flow {#step-5-add-inverse-data-flow} - -

See the Pen Thinking In React: Step 5 on CodePen.

- -So far, we've built an app that renders correctly as a function of props and state flowing down the hierarchy. Now it's time to support data flowing the other way: the form components deep in the hierarchy need to update the state in `FilterableProductTable`. - -React makes this data flow explicit to make it easy to understand how your program works, but it does require a little more typing than traditional two-way data binding. - -If you try to type or check the box in the current version of the example, you'll see that React ignores your input. This is intentional, as we've set the `value` prop of the `input` to always be equal to the `state` passed in from `FilterableProductTable`. - -Let's think about what we want to happen. We want to make sure that whenever the user changes the form, we update the state to reflect the user input. Since components should only update their own state, `FilterableProductTable` will pass callbacks to `SearchBar` that will fire whenever the state should be updated. We can use the `onChange` event on the inputs to be notified of it. The callbacks passed by `FilterableProductTable` will call `setState()`, and the app will be updated. - -Though this sounds complex, it's really just a few lines of code. And it's really explicit how your data is flowing throughout the app. - -## And That's It {#and-thats-it} - -Hopefully, this gives you an idea of how to think about building components and applications with React. While it may be a little more typing than you're used to, remember that code is read far more than it's written, and it's extremely easy to read this modular, explicit code. As you start to build large libraries of components, you'll appreciate this explicitness and modularity, and with code reuse, your lines of code will start to shrink. :) +--- +id: thinking-in-react +title: React처럼 사고하기 +permalink: docs/thinking-in-react.html +redirect_from: + - 'blog/2013/11/05/thinking-in-react.html' + - 'docs/thinking-in-react-zh-CN.html' +prev: composition-vs-inheritance.html +--- + +React 는 JavaScript로 규모가 크고 빠른 웹 애플리케이션을 만드는 가장 좋은 방법입니다. React는 Facebook과 Instagram을 통해 확장성을 입증했습니다. + +React의 가장 멋진 점 중 하나는 앱을 설계하는 방식입니다. 이 문서를 통해 리액트로 상품들을 검색할 수 있는 데이터 테이블을 만드는 과정을 함께 생각해 봅시다. + +## 목업으로 시작하기 {#start-with-a-mock} + + JSON API와 목업을 디자이너로부터 받았다고 가정해 봅시다. 목업은 다음과 같을 것입니다. + +![목업](../images/blog/thinking-in-react-mock.png) + +JSON API는 아래와 같은 데이터를 반환합니다. + +``` +[ + {category: "Sporting Goods", price: "$49.99", stocked: true, name: "Football"}, + {category: "Sporting Goods", price: "$9.99", stocked: true, name: "Baseball"}, + {category: "Sporting Goods", price: "$29.99", stocked: false, name: "Basketball"}, + {category: "Electronics", price: "$99.99", stocked: true, name: "iPod Touch"}, + {category: "Electronics", price: "$399.99", stocked: false, name: "iPhone 5"}, + {category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7"} +]; +``` + +## 1단계: UI를 컴포넌트 계층 구조로 나누기 {#step-1-break-the-ui-into-a-component-hierarchy} + +우리가 할 첫 번째 일은 모든 컴포넌트(와 하위 컴포넌트)의 주변에 박스를 그리고 그 각각에 이름을 붙이는 것입니다. 만약 디자이너와 함께 일한다면, 이것들을 이미 정해두었을 수 있으니 한번 대화해보세요! 디자이너의 Photoshop 레이어 이름이 React 컴포넌트의 이름이 될 수 있습니다. + +하지만 어떤 것이 컴포넌트가 되어야 할지 어떻게 알 수 있을까요? 우리가 새로운 함수나 객체를 만들 때처럼 만드시면 됩니다. 한 가지 테크닉은 [단일 책임 원칙](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99)입니다. 이는 하나의 컴포넌트는 한 가지 일을 하는게 이상적이라는 원칙입니다. 만약 하나의 컴포넌트가 커지게 된다면 이는 보다 작은 하위 컴포넌트로 분리되어야 합니다. + + 주로 JSON 데이터를 유저에게 보여주기 때문에, 만약 데이터 모델이 적절하게 만들어졌다면, UI(컴포넌트 구조)가 잘 매핑될 것입니다. 이는 UI와 데이터 모델이 같은 *인포메이션 아키텍처(information architecture)*로 잘 연결되기 때문입니다. 이 말은 UI를 컴포넌트로 세분화 시키기가 쉽다는 의미이기도 합니다. 각 컴포넌트가 데이터 모델의 한 조각을 나타내도록 분리하면 됩니다. + +![Component diagram](../images/blog/thinking-in-react-components.png) + +다섯개의 컴포넌트로 이루어진 간단한 앱을 한번 봅시다. 각각의 컴포넌트에 들어간 데이터는 이탤릭체로 표현했습니다. + + 1. **`FilterableProductTable`(노란색)**: 예시 전체를 포괄합니다. + 2. **`SearchBar`(파란색)**: 모든 *유저의 입력(user input)* 을 받습니다. + 3. **`ProductTable`(연두색)**: *유저의 입력(user input)*을 기반으로 *데이터 콜렉션(data collection)*을 필터링 해서 보여줍니다. + 4. **`ProductCategoryRow`(하늘색)**: 각 *카테고리(category)*의 헤더를 보여줍니다. + 5. **`ProductRow`(빨강색)**: 각각의 *제품(product)*에 해당하는 행을 보여줍니다. + +`ProductTable`을 보면 “Name” 과 “Price” 레이블을 포함한 테이블 헤더만을 가진 컴포넌트는 없습니다. 이는 선호의 문제이며 어느 쪽으로 선택할 지는 선택입니다. 이 예시에서는 `ProductTable`의 책임인 *데이터 컬렉션(data collection)*이 렌더링의 일부이기 때문에 `ProductTable`을 남겨두었습니다. 그러나 이 헤더가 복잡해지면 (즉 정렬을 위한 기능을 추가하는 등) `ProductTableHeader`컴포넌트를 만드는 것이 더 합리적일 것입니다. + +이제 목업에서 컴포넌트를 확인하였으므로 이를 계층 구조로 나열해봅시다. 이 작업은 쉽습니다. 모형의 다른 컴포넌트 내부에 나타나는 컴포넌트는 계층 구조의 자식으로 나타냅니다. + + * `FilterableProductTable` + * `SearchBar` + * `ProductTable` + * `ProductCategoryRow` + * `ProductRow` + +## 2단계: React로 정적인 버전 만들기 {#step-2-build-a-static-version-in-react} + +

CodePen에서Thinking In React: Step 2를 살펴보세요.

+ + +이제 컴포넌트 계층구조가 만들어졌으니 앱을 실제로 구현해볼 시간입니다. 가장 쉬운 방법은 데이터 모델을 가지고 UI를 렌더링은 되지만 아무 동작도 없는 버전을 만들어보는 것입니다. 이처럼 과정을 나누는 것이 좋은데 정적 버전을 만드는 것은 생각은 적게 필요하지만 타이핑은 많이 필요로 하고, 상호작용을 만드는 것은 생각은 많이 해야 하지만 타이핑은 적게 필요로 하기 때문입니다. 나중에 보다 자세히 살펴봅시다. + +데이터 모델을 렌더링하는 앱의 정적 버전을 만들기 위해 다른 컴포넌트를 재사용하는 컴포넌트를 만들고 props 를 이용해 데이터를 전달해줍시다. props는 부모가 자식에게 데이터를 넘겨줄 때 사용할 수 있는 방법입니다. 만약 state 에 대해 알고 있다면 정적 버전을 만들기 위해 **state를 사용하지 마세요**. state는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용합니다. 우리는 앱의 정적 버전을 만들고 있기 때문에 지금은 필요하지 않습니다. + +앱을 만들 때 하향식(top-down)이나 상향식(bottom-up)으로 만들 수 있습니다. 다시 말해 계층 구조의 상층부에 있는 컴포넌트 (즉 `FilterableProductTable`부터 시작하는 것)부터 만들거나 하층부에 있는 컴포넌트 (`ProductRow`) 부터 만들 수도 있습니다. 간단한 예시에서는 보통 하향식으로 만드는 게 쉽지만 프로젝트가 커지면 상향식으로 만들고 테스트를 작성하면서 개발하기가 더 쉽습니다. + +이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 render() 메서드만 가지고 있을 것입니다. 계층구조의 최상단 컴포넌트 (`FilterableProductTable`)는 prop으로 데이터 모델을 받습니다. 데이터 모델이 변경되면 `ReactDOM.render()`를 다시 호출하서 UI가 업데이트 됩니다. 지금 단계서 어떻게 UI가 업데이트되는지 확인하는 일은 어렵지 않은데 지금은 크게 복잡한 부분이 없기 때문입니다. React의 **단방향 데이터 흐름(one-way data flow)** (또는 *단방향 바인딩(one-way binding*))는 모든 것을 모듈화 하고 빠르게 만들어줍니다. + +이 단계를 실행하는데 어려움이 있다면 [공식 리액트 문서](/docs/)를 참고하세요. + +### 짧은 소개: Props vs State {#a-brief-interlude-props-vs-state} + +React 에는 두가지 데이터 “모델”인 props와 state가 있습니다. 이 둘 사이의 차이점을 이해하는 것이 중요합니다. 만약 차이점이 제대로 기억나지 않는다면 [공식 리액트 문서](/docs/interactivity-and-dynamic-uis.html)를 살펴보세요. + +## 3단계: UI state에 대한 최소한의 (하지만 완전한) 표현 찾아내기 {#step-3-identify-the-minimal-but-complete-representation-of-ui-state} + +UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 있는 방법이 있어야 합니다. React의 **state**는 이를 쉽게 만들어 줍니다. + +애플리케이션을 올바르게 만들기 위해서는 애플리케이션에서 필요로 하는 변경 가능한 state의 최소 집합을 생각해보아야 합니다. 여기서 핵심은 [중복배제](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)원칙입니다. 애플리케이션이 필요로 하는 가장 최소한의 state를 찾고 이를 통해 나머지 모든 것들이 필요에 따라 그때그때 계산되도록 만드세요. 예를 들어 TODO 리스트를 만든다고 하면, TODO 아이템을 저장하는 배열만 유지하고 TODO 아이템의 개수를 표현하는 state를 별도로 만들지 마세요. 만약 TODO 갯수를 렌더링해야한다면 TODO 아이템 배열의 길이를 가져오면 됩니다. + +예시 애플리케이션 내 데이터들을 생각해봅시다. 우리는 현재, + + * 제품의 원본 목록 + * 유저가 입력한 검색어 + * 체크박스의 값 + * 필터링 된 제품들의 목록 + +각각 살펴보고 어떤 게 state가 되어야 하는 지 살펴봅시다. 이는 각 데이터에 대해 아래의 세 가지 질문을 통해 결정할 수 있습니다. + + 1. 부모로부터 props를 통해 전달됩니까? 그러면 확실히 state가 아닙니다. + 2. 시간이 지나도 변하지 않나요? 그러면 확실히 state가 아닙니다. + 3. 컴포넌트 안의 다른 state나 props를 가지고 계산 가능한가요? 그렇다면 state가 아닙니다. + +제품의 원본 목록은 props를 통해 전달되므로 state가 아닙니다. 검색어와 체크박스는 state로 볼 수 있는데 시간이 지남에 따라 변하기도 하면서 다른 것들로부터 계산될 수 없기 때문입니다. 그리고 마지막으로 필터링된 목록은 state가 아닙니다. 제품의 원본 목록과 검색어, 체크박스의 값을 조합해서 계산해낼 수 있기 때문입니다. + +결과적으로 state는 + + * 유저가 입력한 검색어 + * 체크박스의 값 + +## 4단계: State가 어디에 있어야 할 지 찾기{#step-4-identify-where-your-state-should-live} + +

CodePen에서 Thinking In React: Step 4를 살펴보세요.

+ +좋습니다. 이제 앱에서 최소한으로 필요한 state가 뭔지 찾아냈습니다. 다음으로는 어떤 컴포넌트가 state를 변경하거나 **소유**할지 찾아야 합니다. + +기억하세요: React는 항상 컴포넌트 계층구조를 따라 아래로 내려가는 단방향 데이터 흐름을 따릅니다. 어떤 컴포넌트가 어떤 state를 가져야 하는 지 바로 결정하기 어려울 수 있습니다. **많은 초보자가 이 부분을 가장 어려워합니다.** 아래 과정을 따라 결정해 보세요. + +애플리케이션이 가지는 각각의 state에 대해서 + + * state를 기반으로 렌더링하는 모든 컴포넌트를 찾으세요. + * 공통 소유 컴포넌트 (common owner component)를 찾으세요. (계층 구조 내에서 특정 state가 있어야 하는 모든 컴포넌트들의 위에 있는 하나의 컴포넌트). + * 공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 합니다. + * state를 소유할 적절한 컴포넌트를 찾지 못하였다면, 단순히 state를 소유하는 컴포넌트를 하나 만들어서 공통 오너 컴포넌트의 상위 계층에 추가하세요. + +이 전략을 애플리케이션에 적용해봅시다. + + * `ProductTable`은 state에 의존한 상품 리스트의 필터링해야 하고 `SearchBar`는 검색어와 체크박스의 상태를 표시해주어야 합니다. + * 공통 소유 컴포넌트는 `FilterableProductTable`입니다. + * 의미상으로도 `FilterableProductTable`이 검색어와 체크박스의 체크 여부를 가지는 것이 타당합니다. + +좋습니다. state를 `FilterableProductTable`에 두기로 했습니다. 먼저 인스턴스 속성인 `this.state = {filterText: '', inStockOnly: false}` 를 `FilterableProductTable`의 `constructor`에 추가하여 애플리케이션의 초기 상태를 반영합니다. 그리고 나서 `filterText`와 `inStockOnly`를 `ProductTable`와 `SearchBar`에 prop으로 전달합니다. 마지막으로 이 props를 사용하여 `ProductTable`의 행을 정렬하고 `SearchBar`의 폼 필드 값을 설정하세요. + +이제 애플리케이션의 동작을 볼 수 있습니다. `filterText`를 `"ball"`로 설정하고 앱을 새로고침 해보세요. 데이터 테이블이 올바르게 업데이트 된 것을 볼 수 있습니다. + +## 5단계: 역방향 데이터 흐름 추가하기 {#step-5-add-inverse-data-flow} + +

CodePen에서 Thinking In React: Step 5를 살펴보세요.

+ +지금까지 우리는 계층 구조 아래로 흐르는 props와 state의 함수로써 앱을 만들었습니다. 이제 다른 방향의 데이터 흐름을 만들어볼 시간입니다. 계층 구조의 하단에 있는 폼 컴포넌트에서 `FilterableProductTable`의 state를 업데이트할 수 있어야 합니다. + +React는 전통적인 양방향 데이터 바인딩(two-way data binding)과 비교하면 더 많은 타이핑을 필요로 하지만 데이터 흐름을 명시적으로 보이게 만들어서 프로그램이 어떻게 동작하는 지 쉽게 파악할 수 있게 합니다. + +우리가 어떤 걸 원하는지 생각해봅시다. 우리는 사용자가 폼을 변경할 때마다 사용자의 입력을 반영할 수 있도록 state를 업데이트하기를 원합니다. 컴포넌트는 그 자신의 state만 변경할 수 있기 때문에 `FilterableProductTable`는 `SearchBar`에 콜백을 넘겨서 state가 업데이트되어야 할 때마다 호출되도록 할 것입니다. 우리는 input에 onChange 이벤트를 사용해서 알림을 받을 수 있습니다. `FilterableProductTable`에서 전달된 콜백은 `setState()`를 호출하고 앱이 업데이트될 것입니다. + +복잡해 보이지만 코드에선 몇줄밖에 안됩니다. 그리고 이를 통해 앱 전체적으로 데이터가 흐르는 모습을 명시적으로 볼 수 있습니다. + +## 이게 전부입니다. {#and-thats-it} + +이 글을 통해 React를 가지고 애플리케이션과 컴포넌트를 만드는 데에 대한 사고방식을 얻어갈 수 있기를 바랍니다. 이전보다 더 많은 타이핑을 해야 할 수 있지만, 코드를 쓸 일보다 읽을 일이 더 많다는 사실을 기억하세요. 모듈화되고 명시적인 코드는 정말 읽기 쉬워집니다. 큰 컴포넌트 라이브러리를 만들게 되면 이 명시성과 모듈성에 감사할 것이며 코드 재사용성을 통해 코드 라인이 줄어들기 시작할 것입니다. :) \ No newline at end of file From 56c6f6d96729987982e09cae3a273145548c7b5f Mon Sep 17 00:00:00 2001 From: yesjin-git Date: Mon, 25 Mar 2019 00:19:05 +0900 Subject: [PATCH 2/4] fix 1st review --- content/docs/thinking-in-react.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/content/docs/thinking-in-react.md b/content/docs/thinking-in-react.md index fd3171e4f..0e148efd6 100644 --- a/content/docs/thinking-in-react.md +++ b/content/docs/thinking-in-react.md @@ -49,7 +49,7 @@ JSON API는 아래와 같은 데이터를 반환합니다. 4. **`ProductCategoryRow`(하늘색)**: 각 *카테고리(category)*의 헤더를 보여줍니다. 5. **`ProductRow`(빨강색)**: 각각의 *제품(product)*에 해당하는 행을 보여줍니다. -`ProductTable`을 보면 “Name” 과 “Price” 레이블을 포함한 테이블 헤더만을 가진 컴포넌트는 없습니다. 이는 선호의 문제이며 어느 쪽으로 선택할 지는 선택입니다. 이 예시에서는 `ProductTable`의 책임인 *데이터 컬렉션(data collection)*이 렌더링의 일부이기 때문에 `ProductTable`을 남겨두었습니다. 그러나 이 헤더가 복잡해지면 (즉 정렬을 위한 기능을 추가하는 등) `ProductTableHeader`컴포넌트를 만드는 것이 더 합리적일 것입니다. +`ProductTable`을 보면 “Name” 과 “Price” 레이블을 포함한 테이블 헤더만을 가진 컴포넌트는 없습니다. 이와 같은 경우, 데이터를 위한 독립된 컴포넌트를 생성할지 생성하지 않을지는 선택입니다. 이 예시에서는 `ProductTable`의 책임인 *데이터 컬렉션(data collection)*이 렌더링의 일부이기 때문에 `ProductTable`을 남겨두었습니다. 그러나 이 헤더가 복잡해지면 (즉 정렬을 위한 기능을 추가하는 등) `ProductTableHeader`컴포넌트를 만드는 것이 더 합리적일 것입니다. 이제 목업에서 컴포넌트를 확인하였으므로 이를 계층 구조로 나열해봅시다. 이 작업은 쉽습니다. 모형의 다른 컴포넌트 내부에 나타나는 컴포넌트는 계층 구조의 자식으로 나타냅니다. @@ -70,7 +70,7 @@ JSON API는 아래와 같은 데이터를 반환합니다. 앱을 만들 때 하향식(top-down)이나 상향식(bottom-up)으로 만들 수 있습니다. 다시 말해 계층 구조의 상층부에 있는 컴포넌트 (즉 `FilterableProductTable`부터 시작하는 것)부터 만들거나 하층부에 있는 컴포넌트 (`ProductRow`) 부터 만들 수도 있습니다. 간단한 예시에서는 보통 하향식으로 만드는 게 쉽지만 프로젝트가 커지면 상향식으로 만들고 테스트를 작성하면서 개발하기가 더 쉽습니다. -이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 render() 메서드만 가지고 있을 것입니다. 계층구조의 최상단 컴포넌트 (`FilterableProductTable`)는 prop으로 데이터 모델을 받습니다. 데이터 모델이 변경되면 `ReactDOM.render()`를 다시 호출하서 UI가 업데이트 됩니다. 지금 단계서 어떻게 UI가 업데이트되는지 확인하는 일은 어렵지 않은데 지금은 크게 복잡한 부분이 없기 때문입니다. React의 **단방향 데이터 흐름(one-way data flow)** (또는 *단방향 바인딩(one-way binding*))는 모든 것을 모듈화 하고 빠르게 만들어줍니다. +이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 `render()` 메서드만 가지고 있을 것입니다. 계층구조의 최상단 컴포넌트 (`FilterableProductTable`)는 prop으로 데이터 모델을 받습니다. 데이터 모델이 변경되면 `ReactDOM.render()`를 다시 호출하서 UI가 업데이트 됩니다. 지금 단계서 어떻게 UI가 업데이트되는지 확인하는 일은 어렵지 않은데 지금은 크게 복잡한 부분이 없기 때문입니다. React의 **단방향 데이터 흐름(one-way data flow)** (또는 *단방향 바인딩(one-way binding*))는 모든 것을 모듈화 하고 빠르게 만들어줍니다. 이 단계를 실행하는데 어려움이 있다면 [공식 리액트 문서](/docs/)를 참고하세요. @@ -135,9 +135,11 @@ UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 지금까지 우리는 계층 구조 아래로 흐르는 props와 state의 함수로써 앱을 만들었습니다. 이제 다른 방향의 데이터 흐름을 만들어볼 시간입니다. 계층 구조의 하단에 있는 폼 컴포넌트에서 `FilterableProductTable`의 state를 업데이트할 수 있어야 합니다. -React는 전통적인 양방향 데이터 바인딩(two-way data binding)과 비교하면 더 많은 타이핑을 필요로 하지만 데이터 흐름을 명시적으로 보이게 만들어서 프로그램이 어떻게 동작하는 지 쉽게 파악할 수 있게 합니다. +React는 전통적인 양방향 데이터 바인딩(two-way data binding)과 비교하면 더 많은 타이핑을 필요로 하지만 데이터 흐름을 명시적으로 보이게 만들어서 프로그램이 어떻게 동작하는지 쉽게 파악할 수 있게 합니다. -우리가 어떤 걸 원하는지 생각해봅시다. 우리는 사용자가 폼을 변경할 때마다 사용자의 입력을 반영할 수 있도록 state를 업데이트하기를 원합니다. 컴포넌트는 그 자신의 state만 변경할 수 있기 때문에 `FilterableProductTable`는 `SearchBar`에 콜백을 넘겨서 state가 업데이트되어야 할 때마다 호출되도록 할 것입니다. 우리는 input에 onChange 이벤트를 사용해서 알림을 받을 수 있습니다. `FilterableProductTable`에서 전달된 콜백은 `setState()`를 호출하고 앱이 업데이트될 것입니다. +현재 상태에서 input box를 체크하거나 키보드를 타이핑할 경우 React가 입력을 무시하는 것을 확인할 수 있습니다. 이는 `input`태그의 `value`속성이 항상 `FilterableProductTable`에서 전달된 state와 동일하도록 설정했기 때문입니다. + +우리가 원하는 것이 무엇인지를 한번 생각해봅시다. 우리는 사용자가 폼을 변경할 때마다 사용자의 입력을 반영할 수 있도록 state를 업데이트하기를 원합니다. 컴포넌트는 그 자신의 state만 변경할 수 있기 때문에 `FilterableProductTable`는 `SearchBar`에 콜백을 넘겨서 state가 업데이트되어야 할 때마다 호출되도록 할 것입니다. 우리는 input에 onChange 이벤트를 사용해서 알림을 받을 수 있습니다. `FilterableProductTable`에서 전달된 콜백은 `setState()`를 호출하고 앱이 업데이트될 것입니다. 복잡해 보이지만 코드에선 몇줄밖에 안됩니다. 그리고 이를 통해 앱 전체적으로 데이터가 흐르는 모습을 명시적으로 볼 수 있습니다. From 2f1964a0ea9317e1f16226f36e8cacb52edaa49e Mon Sep 17 00:00:00 2001 From: Eungjin Kim <44359045+yesjin-git@users.noreply.github.com> Date: Sun, 21 Apr 2019 23:32:26 +0900 Subject: [PATCH 3/4] Update thinking-in-react.md --- content/docs/thinking-in-react.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/content/docs/thinking-in-react.md b/content/docs/thinking-in-react.md index 0e148efd6..b4a1d8c73 100644 --- a/content/docs/thinking-in-react.md +++ b/content/docs/thinking-in-react.md @@ -1,6 +1,6 @@ --- id: thinking-in-react -title: React처럼 사고하기 +title: React로 사고하기 permalink: docs/thinking-in-react.html redirect_from: - 'blog/2013/11/05/thinking-in-react.html' @@ -8,9 +8,9 @@ redirect_from: prev: composition-vs-inheritance.html --- -React 는 JavaScript로 규모가 크고 빠른 웹 애플리케이션을 만드는 가장 좋은 방법입니다. React는 Facebook과 Instagram을 통해 확장성을 입증했습니다. +React는 JavaScript로 규모가 크고 빠른 웹 애플리케이션을 만드는 가장 좋은 방법입니다. React는 Facebook과 Instagram을 통해 확장성을 입증했습니다. -React의 가장 멋진 점 중 하나는 앱을 설계하는 방식입니다. 이 문서를 통해 리액트로 상품들을 검색할 수 있는 데이터 테이블을 만드는 과정을 함께 생각해 봅시다. +React의 가장 멋진 점 중 하나는 앱을 설계하는 방식입니다. 이 문서를 통해 React로 상품들을 검색할 수 있는 데이터 테이블을 만드는 과정을 함께 생각해 봅시다. ## 목업으로 시작하기 {#start-with-a-mock} @@ -33,11 +33,11 @@ JSON API는 아래와 같은 데이터를 반환합니다. ## 1단계: UI를 컴포넌트 계층 구조로 나누기 {#step-1-break-the-ui-into-a-component-hierarchy} -우리가 할 첫 번째 일은 모든 컴포넌트(와 하위 컴포넌트)의 주변에 박스를 그리고 그 각각에 이름을 붙이는 것입니다. 만약 디자이너와 함께 일한다면, 이것들을 이미 정해두었을 수 있으니 한번 대화해보세요! 디자이너의 Photoshop 레이어 이름이 React 컴포넌트의 이름이 될 수 있습니다. +우리가 할 첫 번째 일은 모든 컴포넌트(와 하위 컴포넌트)의 주변에 박스를 그리고 그 각각에 이름을 붙이는 것입니다. 디자이너와 함께 일한다면, 이것들을 이미 정해두었을 수 있으니 한번 대화해보세요! 디자이너의 Photoshop 레이어 이름이 React 컴포넌트의 이름이 될 수 있습니다. -하지만 어떤 것이 컴포넌트가 되어야 할지 어떻게 알 수 있을까요? 우리가 새로운 함수나 객체를 만들 때처럼 만드시면 됩니다. 한 가지 테크닉은 [단일 책임 원칙](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99)입니다. 이는 하나의 컴포넌트는 한 가지 일을 하는게 이상적이라는 원칙입니다. 만약 하나의 컴포넌트가 커지게 된다면 이는 보다 작은 하위 컴포넌트로 분리되어야 합니다. +하지만 어떤 것이 컴포넌트가 되어야 할지 어떻게 알 수 있을까요? 우리가 새로운 함수나 객체를 만들 때처럼 만드시면 됩니다. 한 가지 테크닉은 [단일 책임 원칙](https://ko.wikipedia.org/wiki/%EB%8B%A8%EC%9D%BC_%EC%B1%85%EC%9E%84_%EC%9B%90%EC%B9%99)입니다. 이는 하나의 컴포넌트는 한 가지 일을 하는게 이상적이라는 원칙입니다. 하나의 컴포넌트가 커지게 된다면 이는 보다 작은 하위 컴포넌트로 분리되어야 합니다. - 주로 JSON 데이터를 유저에게 보여주기 때문에, 만약 데이터 모델이 적절하게 만들어졌다면, UI(컴포넌트 구조)가 잘 매핑될 것입니다. 이는 UI와 데이터 모델이 같은 *인포메이션 아키텍처(information architecture)*로 잘 연결되기 때문입니다. 이 말은 UI를 컴포넌트로 세분화 시키기가 쉽다는 의미이기도 합니다. 각 컴포넌트가 데이터 모델의 한 조각을 나타내도록 분리하면 됩니다. + 주로 JSON 데이터를 유저에게 보여주기 때문에, 데이터 모델이 적절하게 만들어졌다면, UI(컴포넌트 구조)가 잘 연결될 것입니다. 이는 UI와 데이터 모델이 같은 *인포메이션 아키텍처(information architecture)*로 잘 연결되기 때문입니다. 이 말은 UI를 컴포넌트로 세분화 시키기가 쉽다는 의미이기도 합니다. 각 컴포넌트가 데이터 모델의 한 조각을 나타내도록 분리하면 됩니다. ![Component diagram](../images/blog/thinking-in-react-components.png) @@ -61,28 +61,28 @@ JSON API는 아래와 같은 데이터를 반환합니다. ## 2단계: React로 정적인 버전 만들기 {#step-2-build-a-static-version-in-react} -

CodePen에서Thinking In React: Step 2를 살펴보세요.

+

CodePen에서 Thinking In React: Step 2를 살펴보세요.

이제 컴포넌트 계층구조가 만들어졌으니 앱을 실제로 구현해볼 시간입니다. 가장 쉬운 방법은 데이터 모델을 가지고 UI를 렌더링은 되지만 아무 동작도 없는 버전을 만들어보는 것입니다. 이처럼 과정을 나누는 것이 좋은데 정적 버전을 만드는 것은 생각은 적게 필요하지만 타이핑은 많이 필요로 하고, 상호작용을 만드는 것은 생각은 많이 해야 하지만 타이핑은 적게 필요로 하기 때문입니다. 나중에 보다 자세히 살펴봅시다. -데이터 모델을 렌더링하는 앱의 정적 버전을 만들기 위해 다른 컴포넌트를 재사용하는 컴포넌트를 만들고 props 를 이용해 데이터를 전달해줍시다. props는 부모가 자식에게 데이터를 넘겨줄 때 사용할 수 있는 방법입니다. 만약 state 에 대해 알고 있다면 정적 버전을 만들기 위해 **state를 사용하지 마세요**. state는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용합니다. 우리는 앱의 정적 버전을 만들고 있기 때문에 지금은 필요하지 않습니다. +데이터 모델을 렌더링하는 앱의 정적 버전을 만들기 위해 다른 컴포넌트를 재사용하는 컴포넌트를 만들고 props 를 이용해 데이터를 전달해줍시다. props는 부모가 자식에게 데이터를 넘겨줄 때 사용할 수 있는 방법입니다. 정적 버전을 만들기 위해 **state를 사용하지 마세요**. state는 오직 상호작용을 위해, 즉 시간이 지남에 따라 데이터가 바뀌는 것에 사용합니다. 우리는 앱의 정적 버전을 만들고 있기 때문에 지금은 필요하지 않습니다. 앱을 만들 때 하향식(top-down)이나 상향식(bottom-up)으로 만들 수 있습니다. 다시 말해 계층 구조의 상층부에 있는 컴포넌트 (즉 `FilterableProductTable`부터 시작하는 것)부터 만들거나 하층부에 있는 컴포넌트 (`ProductRow`) 부터 만들 수도 있습니다. 간단한 예시에서는 보통 하향식으로 만드는 게 쉽지만 프로젝트가 커지면 상향식으로 만들고 테스트를 작성하면서 개발하기가 더 쉽습니다. 이 단계가 끝나면 데이터 렌더링을 위해 만들어진 재사용 가능한 컴포넌트들의 라이브러리를 가지게 됩니다. 현재는 앱의 정적 버전이기 때문에 컴포넌트는 `render()` 메서드만 가지고 있을 것입니다. 계층구조의 최상단 컴포넌트 (`FilterableProductTable`)는 prop으로 데이터 모델을 받습니다. 데이터 모델이 변경되면 `ReactDOM.render()`를 다시 호출하서 UI가 업데이트 됩니다. 지금 단계서 어떻게 UI가 업데이트되는지 확인하는 일은 어렵지 않은데 지금은 크게 복잡한 부분이 없기 때문입니다. React의 **단방향 데이터 흐름(one-way data flow)** (또는 *단방향 바인딩(one-way binding*))는 모든 것을 모듈화 하고 빠르게 만들어줍니다. -이 단계를 실행하는데 어려움이 있다면 [공식 리액트 문서](/docs/)를 참고하세요. +이 단계를 실행하는데 어려움이 있다면 [공식 React 문서](/docs/)를 참고하세요. ### 짧은 소개: Props vs State {#a-brief-interlude-props-vs-state} -React 에는 두가지 데이터 “모델”인 props와 state가 있습니다. 이 둘 사이의 차이점을 이해하는 것이 중요합니다. 만약 차이점이 제대로 기억나지 않는다면 [공식 리액트 문서](/docs/interactivity-and-dynamic-uis.html)를 살펴보세요. +React 에는 두가지 데이터 “모델”인 props와 state가 있습니다. 이 둘 사이의 차이점을 이해하는 것이 중요합니다. 차이점이 제대로 기억나지 않는다면 [공식 React 문서](/docs/interactivity-and-dynamic-uis.html)를 살펴보세요. ## 3단계: UI state에 대한 최소한의 (하지만 완전한) 표현 찾아내기 {#step-3-identify-the-minimal-but-complete-representation-of-ui-state} UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 있는 방법이 있어야 합니다. React의 **state**는 이를 쉽게 만들어 줍니다. -애플리케이션을 올바르게 만들기 위해서는 애플리케이션에서 필요로 하는 변경 가능한 state의 최소 집합을 생각해보아야 합니다. 여기서 핵심은 [중복배제](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)원칙입니다. 애플리케이션이 필요로 하는 가장 최소한의 state를 찾고 이를 통해 나머지 모든 것들이 필요에 따라 그때그때 계산되도록 만드세요. 예를 들어 TODO 리스트를 만든다고 하면, TODO 아이템을 저장하는 배열만 유지하고 TODO 아이템의 개수를 표현하는 state를 별도로 만들지 마세요. 만약 TODO 갯수를 렌더링해야한다면 TODO 아이템 배열의 길이를 가져오면 됩니다. +애플리케이션을 올바르게 만들기 위해서는 애플리케이션에서 필요로 하는 변경 가능한 state의 최소 집합을 생각해보아야 합니다. 여기서 핵심은 [중복배제](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)원칙입니다. 애플리케이션이 필요로 하는 가장 최소한의 state를 찾고 이를 통해 나머지 모든 것들이 필요에 따라 그때그때 계산되도록 만드세요. 예를 들어 TODO 리스트를 만든다고 하면, TODO 아이템을 저장하는 배열만 유지하고 TODO 아이템의 개수를 표현하는 state를 별도로 만들지 마세요. TODO 갯수를 렌더링해야한다면 TODO 아이템 배열의 길이를 가져오면 됩니다. 예시 애플리케이션 내 데이터들을 생각해봅시다. 우리는 현재, @@ -115,7 +115,7 @@ UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 애플리케이션이 가지는 각각의 state에 대해서 * state를 기반으로 렌더링하는 모든 컴포넌트를 찾으세요. - * 공통 소유 컴포넌트 (common owner component)를 찾으세요. (계층 구조 내에서 특정 state가 있어야 하는 모든 컴포넌트들의 위에 있는 하나의 컴포넌트). + * 공통 소유 컴포넌트 (common owner component)를 찾으세요. (계층 구조 내에서 특정 state가 있어야 하는 모든 컴포넌트들의 상위에 있는 하나의 컴포넌트). * 공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 합니다. * state를 소유할 적절한 컴포넌트를 찾지 못하였다면, 단순히 state를 소유하는 컴포넌트를 하나 만들어서 공통 오너 컴포넌트의 상위 계층에 추가하세요. @@ -145,4 +145,4 @@ React는 전통적인 양방향 데이터 바인딩(two-way data binding)과 비 ## 이게 전부입니다. {#and-thats-it} -이 글을 통해 React를 가지고 애플리케이션과 컴포넌트를 만드는 데에 대한 사고방식을 얻어갈 수 있기를 바랍니다. 이전보다 더 많은 타이핑을 해야 할 수 있지만, 코드를 쓸 일보다 읽을 일이 더 많다는 사실을 기억하세요. 모듈화되고 명시적인 코드는 정말 읽기 쉬워집니다. 큰 컴포넌트 라이브러리를 만들게 되면 이 명시성과 모듈성에 감사할 것이며 코드 재사용성을 통해 코드 라인이 줄어들기 시작할 것입니다. :) \ No newline at end of file +이 글을 통해 React를 가지고 애플리케이션과 컴포넌트를 만드는 데에 대한 사고방식을 얻어갈 수 있기를 바랍니다. 이전보다 더 많은 타이핑을 해야 할 수 있지만, 코드를 쓸 일보다 읽을 일이 더 많다는 사실을 기억하세요. 모듈화되고 명시적인 코드는 정말 읽기 쉬워집니다. 큰 컴포넌트 라이브러리를 만들게 되면 이 명시성과 모듈성에 감사할 것이며 코드 재사용성을 통해 코드 라인이 줄어들기 시작할 것입니다. :) From 581c86ac9e172b20c7b1a7007aceb9220a7d7965 Mon Sep 17 00:00:00 2001 From: Eungjin Kim <44359045+yesjin-git@users.noreply.github.com> Date: Sun, 5 May 2019 20:55:31 +0900 Subject: [PATCH 4/4] Update thinking-in-react.md --- content/docs/thinking-in-react.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/docs/thinking-in-react.md b/content/docs/thinking-in-react.md index b4a1d8c73..cc455be31 100644 --- a/content/docs/thinking-in-react.md +++ b/content/docs/thinking-in-react.md @@ -41,7 +41,7 @@ JSON API는 아래와 같은 데이터를 반환합니다. ![Component diagram](../images/blog/thinking-in-react-components.png) -다섯개의 컴포넌트로 이루어진 간단한 앱을 한번 봅시다. 각각의 컴포넌트에 들어간 데이터는 이탤릭체로 표현했습니다. +다섯개의 컴포넌트로 이루어진 간단한 앱을 한번 봅시다. 각각의 컴포넌트에 들어간 데이터는 이탤릭체로 표기했습니다. 1. **`FilterableProductTable`(노란색)**: 예시 전체를 포괄합니다. 2. **`SearchBar`(파란색)**: 모든 *유저의 입력(user input)* 을 받습니다. @@ -49,7 +49,7 @@ JSON API는 아래와 같은 데이터를 반환합니다. 4. **`ProductCategoryRow`(하늘색)**: 각 *카테고리(category)*의 헤더를 보여줍니다. 5. **`ProductRow`(빨강색)**: 각각의 *제품(product)*에 해당하는 행을 보여줍니다. -`ProductTable`을 보면 “Name” 과 “Price” 레이블을 포함한 테이블 헤더만을 가진 컴포넌트는 없습니다. 이와 같은 경우, 데이터를 위한 독립된 컴포넌트를 생성할지 생성하지 않을지는 선택입니다. 이 예시에서는 `ProductTable`의 책임인 *데이터 컬렉션(data collection)*이 렌더링의 일부이기 때문에 `ProductTable`을 남겨두었습니다. 그러나 이 헤더가 복잡해지면 (즉 정렬을 위한 기능을 추가하는 등) `ProductTableHeader`컴포넌트를 만드는 것이 더 합리적일 것입니다. +`ProductTable`을 보면 “Name” 과 “Price” 레이블을 포함한 테이블 헤더만을 가진 컴포넌트는 없습니다. 이 같은 경우, 데이터를 위한 독립된 컴포넌트를 생성할지 생성하지 않을지는 선택입니다. 이 예시에서는 `ProductTable`의 책임인 *데이터 컬렉션(data collection)*이 렌더링의 일부이기 때문에 `ProductTable`을 남겨두었습니다. 그러나 이 헤더가 복잡해지면 (즉 정렬을 위한 기능을 추가하는 등) `ProductTableHeader`컴포넌트를 만드는 것이 더 합리적일 것입니다. 이제 목업에서 컴포넌트를 확인하였으므로 이를 계층 구조로 나열해봅시다. 이 작업은 쉽습니다. 모형의 다른 컴포넌트 내부에 나타나는 컴포넌트는 계층 구조의 자식으로 나타냅니다. @@ -84,7 +84,7 @@ UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 애플리케이션을 올바르게 만들기 위해서는 애플리케이션에서 필요로 하는 변경 가능한 state의 최소 집합을 생각해보아야 합니다. 여기서 핵심은 [중복배제](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)원칙입니다. 애플리케이션이 필요로 하는 가장 최소한의 state를 찾고 이를 통해 나머지 모든 것들이 필요에 따라 그때그때 계산되도록 만드세요. 예를 들어 TODO 리스트를 만든다고 하면, TODO 아이템을 저장하는 배열만 유지하고 TODO 아이템의 개수를 표현하는 state를 별도로 만들지 마세요. TODO 갯수를 렌더링해야한다면 TODO 아이템 배열의 길이를 가져오면 됩니다. -예시 애플리케이션 내 데이터들을 생각해봅시다. 우리는 현재, +예시 애플리케이션 내 데이터들을 생각해봅시다. 애플리케이션은 다음과 같은 데이터를 가지고 있습니다. * 제품의 원본 목록 * 유저가 입력한 검색어 @@ -99,7 +99,7 @@ UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 제품의 원본 목록은 props를 통해 전달되므로 state가 아닙니다. 검색어와 체크박스는 state로 볼 수 있는데 시간이 지남에 따라 변하기도 하면서 다른 것들로부터 계산될 수 없기 때문입니다. 그리고 마지막으로 필터링된 목록은 state가 아닙니다. 제품의 원본 목록과 검색어, 체크박스의 값을 조합해서 계산해낼 수 있기 때문입니다. -결과적으로 state는 +결과적으로 애플리케이션은 다음과 같은 state를 가집니다. * 유저가 입력한 검색어 * 체크박스의 값 @@ -116,7 +116,7 @@ UI를 상호작용하게 만들려면 기반 데이터 모델을 변경할 수 * state를 기반으로 렌더링하는 모든 컴포넌트를 찾으세요. * 공통 소유 컴포넌트 (common owner component)를 찾으세요. (계층 구조 내에서 특정 state가 있어야 하는 모든 컴포넌트들의 상위에 있는 하나의 컴포넌트). - * 공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 합니다. + * 공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 합니다. * state를 소유할 적절한 컴포넌트를 찾지 못하였다면, 단순히 state를 소유하는 컴포넌트를 하나 만들어서 공통 오너 컴포넌트의 상위 계층에 추가하세요. 이 전략을 애플리케이션에 적용해봅시다. @@ -141,7 +141,7 @@ React는 전통적인 양방향 데이터 바인딩(two-way data binding)과 비 우리가 원하는 것이 무엇인지를 한번 생각해봅시다. 우리는 사용자가 폼을 변경할 때마다 사용자의 입력을 반영할 수 있도록 state를 업데이트하기를 원합니다. 컴포넌트는 그 자신의 state만 변경할 수 있기 때문에 `FilterableProductTable`는 `SearchBar`에 콜백을 넘겨서 state가 업데이트되어야 할 때마다 호출되도록 할 것입니다. 우리는 input에 onChange 이벤트를 사용해서 알림을 받을 수 있습니다. `FilterableProductTable`에서 전달된 콜백은 `setState()`를 호출하고 앱이 업데이트될 것입니다. -복잡해 보이지만 코드에선 몇줄밖에 안됩니다. 그리고 이를 통해 앱 전체적으로 데이터가 흐르는 모습을 명시적으로 볼 수 있습니다. +복잡해 보이지만 코드에선 몇줄밖에 안 됩니다. 그리고 이를 통해 앱 전체적으로 데이터가 흐르는 모습을 명시적으로 볼 수 있습니다. ## 이게 전부입니다. {#and-thats-it}