> For the complete documentation index, see [llms.txt](https://simplereact.gitbook.io/simplereact/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://simplereact.gitbook.io/simplereact/hooks.md).

# (1) 만들면서 알아보는 Hooks

### 프로젝트 구조&#x20;

만들어볼 프로젝트의 구조는 아래와 같습니다.

![](/files/-LvV4u8CqtaWN-tIKvmX)

> 프로젝트는 [초기 세팅 상태](https://simplereact.gitbook.io/simplereact/02.-componet#undefined-1)로 진행되어집니다.&#x20;

### 1) 레이아웃 구성

스타일링을 위해 [styled-components](https://www.styled-components.com/) 를 설치합니다.

```
$ npm i -S styled-components
```

먼저 왼쪽의 목록 컴포넌트부터 만들어보도록 하겠습니다.\
\
목록 컴포넌트가 해주는 일은 간단합니다. \
목록 데이터를 받아 그려줍니다. 목록의 메모를 클릭시 클릭된 메모를 오른쪽에 그려줍니다.\
\
이번 예제에서는 Context API 를 이용하여 데이터의 상호작용이 이루어 질 수 있도록 합니다.

먼저 src 폴더 아래에 memos 폴더와 content 폴더를 만들고 내부에 index.js 들을 생성해주세요

```javascript
// src/memos/index.js

import React from "react";
import styled from "styled-components";

const MemoFrame = styled.div``;

function Memos() { 
  return <MemoFrame>Memos</MemoFrame>;
}

export default Memos;

// src/content/index.js

import React from "react";
import styled from "styled-components";

const ContentFrame = styled.div``;

function Content() { 
  return <ContentFrame>Memo</ContentFrame>;
}

export default Content;
```

> 혹시 styled-component 의 사용법을 잘 모르신다면 이전 예제들을 확인해주세요

만들어진 컴포넌트들을 App.js 에서 불러와서 간단한 레이아웃 구조를 생성해보겠습니다.

```javascript
// src/App.js

import React from "react";
import styled, { css } from "styled-components";

import Memos from "./memos";
import Content "./content";

// 왼쪽 오른쪽 구조를 나눠야 하기 때문에 flex 를 이용합니다.
const AppFrame = styled.div`
  display: flex;
  height: 100vh;
`;

/* 
  나눠진 왼쪽 오른쪽에 flex 사이즈를 유동적으로 조절하기 위해 flex 값을
  props 로 내려받습니다. 
*/
const Container = styled.div`
  ${({ flex }) =>
    flex &&
    css`
      display: flex;
      flex: ${flex};
    `}
`;

function App() {
  return (
    <AppFrame>
      <Container flex={1}>
        <Memos />
      </Container>
      <Container flex={2}>
        <Content />
      </Container>
    </AppFrame>
  );
}

export default App;
```

아래와 같이 나누어진 화면을 보실 수 있을거에요

![](/files/-LvV8VIxqNHb04-0COlP)

### 2) useContext 를 이용하여 Context API 구성

왼쪽 목록의 컴포넌트에서는 선택된 메모의 값을 알아야하고 \
오른쪽 컴포넌트에서는 선택된 메모 값을 바탕으로 데이터를 그려줘야합니다.\
이처럼 컴포넌트들 끼리의 상호작용이 일어날때 가장 간단한 방법은 \
두 컴포넌트를 감싸는 컴포넌트로 state 를 올려서 사용하는 방법이 있지만 \
이번에는 Context API 를 이용하여 데이터를 주고 받는 방법을 알아보려고합니다.

`use-Context` 라는 hook 을 이용하여 Context API 를 보다 손쉽게 사용하도록 할 수 있습니다.

> 다양한 Context 를 만들 수 있는 방법은 [여기](https://simplereact.gitbook.io/simplereact/context-api)를 참고해주세요&#x20;

src 아래에 application-context 라는 이름의 파일을 만들어주세요&#x20;

```javascript
// src/application-context.js

import React, { createContext, useContext, useState } from "react";

// Context 를 생성합니다.
const Context = createContext(null);

// Provider 로 감싸지는 컴포넌트들은 value 의 값을 props 로 받을 수 있습니다.
export function ApplicationContextProvider({ children }) {
  const [memos, setMemos] = useState(null);
  const [memo, setMemo] = useState(null);

  const value = {
    memos,
    setMemos,
    memo,
    setMemo
  };
  return <Context.Provider value={value}>{children}</Context.Provider>;
}

// 외부에서 context 를 손쉽게 가져다 쓸 수 있도록 도와줍니다.
export function useApplicationContext() {
  return useContext(Context);
}
```

> 여기서 잠깐, useState 란 ?

useState 는 이전에 보았던 class component 의 `state = { // ... }` 와 같습니다. 다른 점이 있다면 setState 로 변경했던 것과는 다르게 `useState` 는 해당 state 를 변경 할 수 있는 짝을 지원해 준다는 것입니다.

```javascript
const [count, setCount] = useState(0)

// count 의 값을 바꿀 수 있는 방법은 setCount 를 이용하는 방법뿐이다.
// naming 규칙은 보통 set + state 명 입니다.
```

### 3) 만들어진 Context API 이용하기

Context API 는 말그대도 관련있는 Context 에서만 값을 이용할 수 있도록 만들어 줄 수 있습니다. \
하지만 지금 우리는 Context 범위가 적기 때문에 두 컴포넌트를 감싸고 있는 App.js 에서 Provider 를 적용해주도록 하겠습니다.

```javascript
// src/app.js

import React from "react";
import styled, { css } from "styled-components";

import { ApplicationContextProvider } from "./application-context";

import Memos from "./memos";
import Content from "./content";

const AppFrame = styled.div`
  display: flex;
  height: 100vh;
`;

const Container = styled.div`
  ${({ flex }) =>
    flex &&
    css`
      display: flex;
      flex: ${flex};
    `}
`;

function App() {
  return (
    <ApplicationContextProvider>
      <AppFrame>
        <Container flex={1}>
          <Memos />
        </Container>
        <Container flex={2}>
          <Content />
        </Container>
      </AppFrame>
    </ApplicationContextProvider>
  );
}

export default App;
```

이제 Provider 로 감싸져 있는 내부 요소들에서는 useApplicationContext 를 이용하여 Context 내부 값에 접근 할 수 있습니다.

### 4) Memos 컴포넌트에서 Context API 사용하기

Memos 컴포넌트를 작성하기전에 먼저 Context API의 memos에 *dummy data* 를 채워보고자합니다.&#x20;

메모는 아래와 같은 데이터 구조를 갖습니다.

```javascript
id: number = '메모의 고유한 id'
title: string = '메모의 제목'
content: string = '메모의 내용'
```

useState 는 인자로 default value 를 줄 수 있습니다. memos 의 default Value 로 dummy data 가 추가된 배열을 줍니다.

```javascript
import React, { createContext, useContext, useState } from "react";

const Context = createContext(null);

export function ApplicationContextProvider({ children }) {
  // useState 의 default Value 를 이용하여 값을 채워줍니다. 
  const [memos, setMemos] = useState([
    {
      id: Date.now(),
      title: "임시 메모 데이터",
      content: "임시 메모 데이터의 내용"
    }
  ]);
  const [memo, setMemo] = useState(null);

  const value = {
    memos,
    setMemos,
    memo,
    setMemo
  };
  return <Context.Provider value={value}>{children}</Context.Provider>;
}

export function useApplicationContext() {
  return useContext(Context);
}
```

이제 memos 에서 context api 에 접근하여 memos 데이터가 잘 불러와지는지 확인해보겠습니다.

```javascript
// src/memos/index.js

import React from "react";
import styled from "styled-components";

import { useApplicationContext } from "../application-context";

const MemosFrame = styled.div``;

function Memos() {
  const { memos } = useApplicationContext();
  console.log("memos", memos);

  return <MemosFrame>Memos</MemosFrame>;
}

export default Memos;
```

![](/files/-LvVEMoSq_jrN3biZ1sp)

memos 데이터를 가지고 왼쪽 리스트를 구성해야하는데 레이아웃 그림에서 보신 것 처럼 같은 형식의 구조가 반복되어지고 있습니다.

![](/files/-LvVG62xxeV_dKvEV9P2)

이 컴포넌트를 리스트자체에서 그려주는 것 보다는 memo 라는 컴포넌트를 만들어 따로 그려주는것이 렌더링 이점과 사용 측면에서도 좋기 때문에 따로 분리를 하겠습니다.

memo 컴포넌트는 id, title, content 의 데이터를 props 로 받습니다.

```javascript
// src/memo/index.js

import React from "react";
import styled from "styled-components";

const MemoFrame = styled.div``;

function Memo({ source: { title, content }}) {
  return <MemoFrame>Memo</MemoFrame>;
}

export default Memo;
```

만든 Memo 를 Memo 에서 사용하도록 추가합니다.

```javascript
// src/memos/index.js

import React from "react";
import styled from "styled-components";

import { useApplicationContext } from "../application-context";

import Memo from "../memo";

// MemosFrame style 을 추가합니다.
const MemosFrame = styled.div`
  width: 100%;
  padding: 10px;
  box-sizing: border-box;
  overflow-y: auto;
`;

function Memos() {
  const { memos } = useApplicationContext();
  console.log("memos", memos);

  // 만들어진 Memo 를 가져와 사용합니다.
  return (
    <MemosFrame>
      {memos.map(memo => (
        <Memo key={memo.id} source={memo} />
      ))}
    </MemosFrame>
  );
}

export default Memos;
```

### 5) 공통 컴포넌트 만들기&#x20;

다양한 텍스트를 표현하기 위해 공통적으로 사용할 Text 컴포넌트와 \
컴포넌트들을 감싸줄 Container 만들어보겠습니다.\
\
Text 의 경우 당장의 필요한 속성은 텍스트의 사이즈, 굵기, 말줄임, line-height 입니다.\
앞으로 필요한 속성은 하나씩 추가하면서 살펴보겠습니다.

```javascript
// src/text.js

import styled, { css } from "styled-components";

const Text = styled.div`
  font-size: ${({ size }) => size || 14}px;

  ${({ lineHeight }) =>
    lineHeight &&
    css`
      line-height: ${lineHeight};
    `}

  ${({ bold }) =>
    bold &&
    css`
      font-weight: bold;
    `}

    ${({ ellipsis }) => css`
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: normal;
      word-wrap: break-word;
      display: -webkit-box;
      -webkit-line-clamp: ${ellipsis};
      -webkit-box-orient: vertical;
    `}
`;

export default Text;
```

Container 는 float, margin, padding, display 가 필요합니다.

```javascript
// src/container.js

import styled, { css } from "styled-components";

const Container = styled.div`
  width: 100%;

  ${({ justify }) =>
    justify &&
    css`
      justify-content: ${justify};
    `}

  ${({ margin }) =>
    margin &&
    css`
      margin-top: ${margin.top}px;
      margin-right: ${margin.right}px;
      margin-bottom: ${margin.bottom}px;
      margin-left: ${margin.left}px;
    `}

  ${({ padding }) =>
    padding &&
    css`
      padding-top: ${padding.top}px;
      padding-right: ${padding.right}px;
      padding-bottom: ${padding.bottom}px;
      padding-left: ${padding.left}px;
    `};

  ${({ flex }) =>
    flex &&
    css`
      display: flex;
      flex: ${flex};
    `}
`;

export default Container;
```

App 에 있는 Container 를 공통 Container 로 변경합니다.

```javascript
// src/App.js

import React from "react";
import styled from "styled-components";

import { ApplicationContextProvider } from "./application-context";

import Container from './container'
import Memos from "./memos";
import Content from "./content";

const AppFrame = styled.div`
  display: flex;
  height: 100vh;
`;

function App() {
  return (
    <ApplicationContextProvider>
      <AppFrame>
        <Container flex={1}>
          <Memos />
        </Container>
        <Container flex={2}>
          <Content />
        </Container>
      </AppFrame>
    </ApplicationContextProvider>
  );
}

export default App;
```

### 6) Memo 구성해보기

위에서 만들어 놓은 text 를 이용하여 Memo 컴포넌트를 만들어보겠습니다.

content 부분은 너무 길어질 수 있기 때문에 말줄임을 적용합니다.

```javascript
import React from "react";
import styled from "styled-components";

import Text from "../text";

const MemoFrame = styled.div`
  border: 1px solid #ebebeb;
  border-radius: 5px;
  padding: 10px;

  &:not(:last-child) {
    margin-bottom: 15px;
  }
`;

function Memo({ source: { title, content } }) {
  return (
    <MemoFrame>
      <Text size={16} lineHeight={1.53} bold>
        {title}
      </Text>
      <Text size={15} lineHeight={1.53} ellipsis={2}>
        {content}
      </Text>
    </MemoFrame>
  );
}

export default Memo;
```

![](/files/-LvVRUlcnht44QMHXXA7)

### 7) Content 컴포넌트 구성하기&#x20;

Content 컴포넌트는 선택된 Memo 에 대한 내용을 보여줍니다.

Content 에서는 Context API 의 Memo State 를 사용하여 내용을 구성합니다.\
Context API 에 dummy data 를 추가하여 view 부터 구성해보겠습니다.

우리가 추가해놓았던 임시메모데이터라는 메모가 선택되어졌다고 가정하겠습니다.

```javascript
import React, { createContext, useContext, useState } from "react";

const Context = createContext(null);

export function ApplicationContextProvider({ children }) {
  const [memos, setMemos] = useState([
    {
      id: Date.now(),
      title: "임시 메모 데이터",
      content: "임시 메모 데이터의 내용",
      createdAt: new Date()
    }
  ]);
  
  // memos 와는 다르게 단일 객체입니다.
  const [memo, setMemo] = useState({
    id: Date.now(),
    title: "임시 메모 데이터",
    content: "임시 메모 데이터의 내용",
    createdAt: new Date()
  });

  const value = {
    memos,
    setMemos,
    memo,
    setMemo
  };
  return <Context.Provider value={value}>{children}</Context.Provider>;
}

export function useApplicationContext() {
  return useContext(Context);
}
```

Content 에서 Context API 의 memo 값을 가져옵니다.\
이전에 만들어뒀던 Container 를 이용하여 간격을 조절하고 Text 를 이용하여 텍스트 스타일을 추가합니다

```javascript
// src/content/index.js 

import React from "react";

import { useApplicationContext } from "../application-context";

import Text from "../text";
import Container from "../container";

function Content() {
  const { memo } = useApplicationContext();

  const { title, content } = memo;

  return (
    <Container padding={{ top: 10, right: 10, bottom: 10, left: 10 }}>
      <Container margin={{ bottom: 20 }}>
        <Text size={27} bold>
          {title}
        </Text>
      </Container>
      <Text size={16}>{content}</Text>
    </Container>
  );
}

export default Content;
```

![](/files/-LvVXrbeys1cuZisYFtB)

### 8) Content 컴포넌트 상태에 따른 버튼&#x20;

Content 컴포넌트에선 선택된 Memo 의 내용을 수정 할 수 있습니다.\
Content 본문 윗 쪽에 수정 모드로 전환 할 수 있는 버튼을 추가합니다.

3 가지의 상태에 따라 버튼은 동작과 텍스트가 달라집니다.

1\) 선택된 Memo 가 있고 수정 상태가 아니면 (새 글 작성 + 수정) 버튼을 노출\
2\) 선택된 Memo 가 있고 수정 상태이면 (수정 + 취소) 버튼을 노출 \
3\) 수정 상태가 아니라면 (새 글 작성 노출)

```javascript
// src/content/index.js 

import React, { useState } from "react";
import styled from "styled-components";
import { useApplicationContext } from "../application-context";

import Text from "../text";
import Container from "../container";

const Button = styled.button`
  padding: 5px 15px;
  color: ${({ active }) => (active ? "#fff" : "#368fff")};
  background: ${({ active }) => (active ? "#368fff" : "#fff")};
  border: 1px solid #368fff;
  border-radius: 2px;
  font-size: 13px;
  font-weight: bold;

  &:not(:last-child) {
    margin-right: 5px;
  }
`;

function Content() {
  const { memo } = useApplicationContext();
  // 후에 메모를 수정 할 때 사용될 state 입니다.
  const [editMemo] = useState({
    title: "", // 수정 할 타이틀
    content: "", // 수정 할 컨텐츠
    isEditing: false // 수정 모드인지
  });

  const { title, content } = memo;
  // 수정 모드를 판단합니다.
  const { isEditing } = editMemo;

  return (
    <Container padding={{ top: 10, right: 10, bottom: 10, left: 10 }}>
      <Container flex justify="flex-end">
        {memo && !isEditing && <Button active>수정</Button>}
        {memo && isEditing && (
          <>
            <Button>취소</Button>
            <Button active>수정</Button>
          </>
        )}
        {!isEditing && <Button>새 글 작성</Button>}
      </Container>
      <Container margin={{ bottom: 20 }}>
        <Text size={27} bold>
          {title}
        </Text>
      </Container>
      <Text size={16}>{content}</Text>
    </Container>
  );
}

export default Content;
```

![](/files/-LvVd5PsXLahoxMtJF2J)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://simplereact.gitbook.io/simplereact/hooks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
