블로깅 주제
- Custom Component
1. 지금 현재, 당신의 기분이나 느낌을 표현해 주세요.
- 좀비같이 일어난 목요일.... 오늘 내일만 버티자! 이러니저러니해도 벌써 10월 마지막 주다.. 코스 시작한지 두 달이 넘었다. 그래, 많이 늘었다. 많이 발전했다. 혼자서 공부했으면 이 정도까지 오지도 못했을 것 같다. 뿌듯하다 ㅎㅎ
2. 오늘 무엇을 학습한 내용 중 지금 떠올릴 수 있는 단어를 모두 나열해 주세요.
- CDD
3. 2에서 작성한 단어를 가지고, 오늘의 학습 내용을 설명해 보세요.
- CDD
▶ CDD란?
기획자로부터 하나의 페이지 기획이 도착했고, 디자이너와 개발자가 협력하여 디자인과 개발이 진행되었다.
페이지가 모두 완성되었는데, 다른 페이지에 적용되는 버튼에 대한 추가적인 기획안이 도착했다.
그런데 기획자가 요청한 사항에서 버튼에 대한 기획이 이전에 요청받았던 버튼을 똑같이 사용하도록 요청했다.
그렇다면 디자이너와 개발자는 이 부분을 모두 새로 만들어야 하는 걸까?
디자인과 개발 단계에서부터 재사용할 수 있는 UI 컴포넌트를 미리 디자인하고 개발하면 이런 고민을 해결할 수 있다.
이 고민을 해결하기 위해 등장한 개발 방법이 바로 Component Driven Development (CDD) 다. 레고처럼 조립해 나갈 수 있는 부품 단위로 UI 컴포넌트를 만들어 나가는 개발을 진행할 수 있다.
▶ CSS in JS
구조화된 CSS가 필요한 이유
인터넷이 만들어진 이후 기술의 발달과 함께 사용자들은 다양한 환경(디바이스)에서 인터넷을 사용하기 시작했다. 이에 따라 개발자들의 CSS 작성 방식도 꾸준히 진화해 오고 있다.
프로젝트의 규모나 복잡도가 점점 커지고 함께 작업해야 할 팀원 수도 많아짐에 따라 CSS를 작성하는 일관된 패턴이 없다는 것은 개발자들에게 가장 큰 걸림돌이 되었다. 또한 모바일이나 태블릿을 비롯한 다양한 디바이스들의 등장으로 웹사이트들이 다양한 디스플레이를 커버해야 하기 때문에 CSS는 더 복잡해지게 되었다.
따라서 CSS 작업을 효율적으로 하기 위해 구조화된 CSS의 필요성이 대두되었고, CSS를 구조화하는 방법에 대한 연구가 필요해졌다.
CSS 전처리기의 등장
이러한 문제점들을 해결하기 위해 CSS 전처리기(CSS Preprocessor)라는 개념이 등장했다.
CSS 전처리기(CSS Preprocessor)란 CSS가 구조적으로 작성될 수 있게 도움을 주는 도구이다.
우리가 흔히 CSS 문서를 작성할 때는 많은 반복적인 작업을 요구하고 Color 값을 찾는 일, tag를 닫는 일 등 번거로운 작업 역시 포함이 되어 있다. 그뿐만 아니라 클래스의 상속과 같은 사항으로 점점 CSS 문서는 양이 많아지고 이로 인해 이후 유지관리에 많은 영향을 끼친다. 이런 CSS의 문제점들을 프로그래밍 개념(변수, 함수, 상속 등)을 활용하여 해결해 나갈 수 있다.
하지만 이 CSS 전처리기(CSS Preprocessor) 자체만으로는 웹 서버가 인지하지 못하기 때문에 각 CSS 전처리기에 맞는 Compiler를 사용해야 하고 컴파일을 하게 되면 실제로 우리가 사용하는 CSS 문서로 변환이 된다.
이를 통해 CSS 파일들을 잘 구조화할 수 있게 되었고, 최소한 CSS 파일을 몇 개의 작은 파일로 분리할 수 있는 방법이 생겼다.
Sass
CSS 전처리기 중에서 가장 유명한 SASS는 Syntactically Awesome Style Sheets의 약자로 CSS를 확장해 주는 스크립팅 언어이다. 즉, CSS를 만들어주는 언어로서 자바스크립트처럼 특정 속성(ex. color, margin, width 등)의 값(ex. #ffffff, 25rem, 100px 등)을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한 번의 선언으로 여러 곳에서 재사용할 수 있도록 해 주는 등의 기능을 가졌다. 그래서 SASS는 SCSS 코드를 읽어서 전처리한 다음 컴파일해서 전역 CSS 번들 파일을 만들어 주는 전처리기(preprocessor)의 역할을 한다.
하지만 얼마 지나지 않아서 SASS가 ‘CSS의 구조화’를 해결해 주는 것의 장점보다 다른 문제들을 더 많이 만들어낸다는 것이 밝혀진다. 결국 우리는 전처리기(preprocessor)가 내부에서 어떤 작업을 하는지는 알지 못한 채, 스타일이 겹치는 문제를 해결하기 위해 단순히 계층 구조를 만들어 내는 것에 의지하게 되었고, 그 결과 컴파일된 CSS의 용량은 어마어마하게 커지게 되었다.
css 방법론의 대두
이러한 CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두되었다. 각각의 장단점이 있으나 결국 세 방법론 모두 같은 지향점을 가지고 있다.
이런 CSS 방법론들은 같이 일하는 팀 동료들의 팀워크와도 연결되기 때문에 여러 팀원이 함께 작업하는 상황에서 CSS 작성에 있어서 방법들을 규칙으로 정해두는 것은 매우 중요한 요소라고 할 수 있다.
BEM
대표적인 CSS 방법론으로는 BEM이 있다.
BEM이란 Block, Element, Modifier로 구분하여 클래스명을 작성하는 방법이며, Block, Element, Modifier 각각은 —와 __로 구분합니다. 클래스명은 BEM 방식의 이름을 여러 번 반복하여 재사용할 수 있도록 하며 HTML/CSS/SASS 파일에서도 더 일관된 코딩 구조를 만들어 준다.
하지만 이러한 방법론들에서도 문제점이 발생하기 시작한다. 클래스명 선택자가 장황해지고, 이런 긴 클래스명 때문에 마크업이 불필요하게 커지며, 재사용하려고 할 때마다 모든 UI 컴포넌트를 명시적으로 확장해야만 했다.
Styled-Component
애플리케이션으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔다. 하지만 CSS는 컴포넌트 기반의 방식을 위해 만들어진 적이 한 번도 없었다. 결국 CSS도 컴포넌트 영역으로 불러들이기 위해 CSS-in-JS가 탄생해서 이 문제를 정확하게 해결한다.
CSS-in-JS에는 대표적으로 Styled-Component가 있다.
Styled-Component는 기능적(Functional) 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공한다.
- CDD 개발도구
1. Styled Components
CSS 코드를 다룰 때 다음과 같은 불편함을 느껴본적이 있다!?
- class, id 이름을 짓느라 고민한 적이 있다.
- CSS 파일 안에서 내가 원하는 부분을 찾기 힘들었다.
- CSS 파일이 너무 길어져서 파일을 쪼개서 관리해본 적이 있다.
- 스타일 속성이 겹쳐서 내가 원하는 결과가 나오지 않은 적이 있다.
이런 불편함을 CSS를 컴포넌트화 시킴으로써 해결해주는 라이브러리가 Styled Components 라는 라이브러리이다.
Styled Components는 CSS in JS 라는 개념이 대두되면서 나온 라이브러리이다. 기존에 HTML, CSS, JS 파일로 쪼개서 개발하던 방법에서, React 등의 라이브러리의 등장으로 컴포넌트 단위 개발이 주류가 되었지만, CSS는 그렇지 못했다는 점에서 출발한 개념이다.
CSS in JS 라이브러리를 사용하면 CSS도 쉽게 Javascript 안에 넣어줄 수 있으므로, HTML + JS + CSS까지 묶어서 하나의 JS파일 안에서 컴포넌트 단위로 개발할 수 있게 된다. 이런 CSS in JS 라이브러리 중에서 현재 가장 인기 있는 라이브러리가 바로 Styled Components 이다.
Styled Components 설치
아래의 코드를 터미널에 입력한다.
# with npm
$ npm install --save styled-components
# with yarn
$ yarn add styled-components
Styled Components는 package.json에 다음 코드를 추가하도록 권장하고 있다. 아래의 코드를 추가하면 여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여준다.
{
"resolutions": {
"styled-components": "^5"
}
}
그 다음 Styled Components를 사용할 파일로 불러와주면 사용 준비 완료!
import styled from "styled-components"
Styled Components 문법
1) 컴포넌트 만들기
tyled Components는 ES6의 Templete Literals 문법을 사용한다. 즉, 따옴표가 아닌 백틱(`)을 사용한다.
컴포넌트를 선언한 후 styled.태그종류를 할당하고, 백틱 안에 기존에 CSS를 작성하던 문법과 똑같이 스타일 속성을 작성해주면 된다. 이렇게 만든 컴포넌트를 React 컴포넌트를 사용하듯 리턴문 안에 작성해주면 스타일이 적용된 컴포넌트가 렌더되는 것을 확인할 수 있다.
import styled from "styled-components";
//Styled Components로 컴포넌트를 만들고
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
export default function App() {
// React 컴포넌트를 사용하듯이 사용하면 됩니다.
return <BlueButton>Blue Button</BlueButton>;
}
2) 컴포넌트를 재활용해서 새로운 컴포넌트 만들기
이미 만들어진 컴포넌트를 재활용해서 새로운 컴포넌트를 만들 수도 있다. 컴포넌트를 선언하고 styled() 에 재활용할 컴포넌트를 전달해준 다음, 추가하고 싶은 스타일 속성을 작성해주면 된다.
import styled from "styled-components";
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
//만들어진 컴포넌트를 재활용해 컴포넌트를 만들 수 있습니다.
const BigBlueButton = styled(BlueButton)`
padding: 10px;
margin-top: 10px;
`;
//재활용한 컴포넌트를 재활용할 수도 있습니다.
const BigRedButton = styled(BigBlueButton)`
background-color: red;
`;
export default function App() {
return (
<>
<BlueButton>Blue Button</BlueButton>
<br />
<BigBlueButton>Big Blue Button</BigBlueButton>
<br />
<BigRedButton>Big Red Button</BigRedButton>
</>
);
}
3) Props 활용하기
Styled Component로 만든 컴포넌트도 React 컴포넌트처럼 props를 내려줄 수 있다. 내려준 props 값에 따라서 컴포넌트를 렌더링하는 것도 가능하다.
Styled Components는 템플릿 리터럴 문법( ${ } )을 사용하여 JavaScript 코드를 사용할 수 있다. props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 된다.
Props로 조건부 렌더링하기
위 코드의 경우는 삼항연산자를 활용해 <Button> 컴포넌트에 skyblue 라는 props가 있는지 확인하고, 있으면 배경색으로 skyblue를, 없을 경우 white를 지정해주는 코드이다. 이 코드에 따라 렌더링된 <Button> 컴포넌트는 아래 그림과 같을 것이다.
Button1 의 경우는 skyblue 라는 props가 있어 배경색이 skyblue 로 지정됐고, Button2의 경우는 props가 아예 없어 배경색이 white 로 지정된 것을 확인할 수 있다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
//받아온 prop에 따라 조건부 렌더링이 가능합니다.
const Button1 = styled.button`
background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 skyblue>Button1</Button1>
</>
);
}
Props값으로 렌더링하기
props의 값을 통째로 활용해서 컴포넌트 렌더링에 활용할 수 있다.
똑같이 삼항연산자를 사용하고 있지만, 이번에는 props.color 가 없다면 white를, props.color 가 있다면 props.color의 값을 그대로 가져와서 스타일 속성 값으로 리턴해주고 있는 것을 볼 수 있다. 그 결과 color 라는 이름으로 받은 props의 값으로 배경색이 지정된 것을 확인할 수 있다.
꼭 삼항연산자만 사용해야하는 것은 아니다. JavaScript 코드라면 무엇이든 사용할 수 있으므로 원하는 값을 사용할 수 있도록 함수 코드를 만들어서 사용하면 된다.
import styled from "styled-components";
import GlobalStyle from "./GlobalStyle";
//받아온 prop 값을 그대로 이용해 렌더링할 수도 있습니다
const Button1 = styled.button`
background: ${(props) => (props.color ? props.color : "white")};
`;
//다음과 같은 형식으로도 활용할 수 있습니다.
const Button2 = styled.button`
background: ${(props) => props.color || "white"};
`;
export default function App() {
return (
<>
<GlobalStyle />
<Button1>Button1</Button1>
<Button1 color="orange">Button1</Button1>
<Button1 color="tomato">Button1</Button1>
<br />
<Button2>Button2</Button2>
<Button2 color="pink">Button2</Button2>
<Button2 color="turquoise">Button2</Button2>
</>
);
}
4) 전역 스타일 설정하기
스타일을 컴포넌트로 만들 수 있다는 것은 좋지만, 전역에 스타일을 설정하고 싶을 땐 어떻게하면 좋을까? Styled Components는 이런 경우를 대비한 컴포넌트도 준비해놓았다.
우선 전역 스타일을 설정하기 위해 Styled Components에서 createGlobalStyle 함수를 불러온다.
import { createGlobalStyle } from "styled-components";
그 다음 이 함수를 사용해 CSS 파일에서 작성하듯 설정해주고 싶은 스타일을 작성한다.
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
border-radius : 5px;
}
`
이렇게 만들어진 <GlobalStyle> 컴포넌트를 최상위 컴포넌트에서 사용해주면 전역에 <GlobalStyle> 컴포넌트의 스타일이 적용된다.
function App() {
return (
<>
<GlobalStyle />
<Button>전역 스타일 적용하기</Button>
</>
);
}
실습
import "./styles.css";
import styled from "styled-components";
import { createGlobalStyle } from "styled-components";
const GlobalStyle = createGlobalStyle`
button {
margin: 0.5rem;
}
`;
const Button1 = styled.button`
padding: 1rem;
font-size: 2rem;
background: powderblue;
border-radius: 1rem;
transition: 0.5s;
&:hover{
background: cornflowerblue;
color: white;
transition: 0.5s;
}
`;
export default function App() {
return(
<>
<GlobalStyle />
<Button1>Practice</Button1>
</>
)
}
https://wnsdufdl.tistory.com/109
2. Storybook
Storybook은 UI 개발 즉, Component Driven Development를 하기 위한 도구이다. 각각의 컴포넌트들을 따로 볼 수 있게 구성해 주어 한 번에 하나의 컴포넌트에서 작업할 수 있다. 복잡한 개발 스택을 시작하거나, 특정 데이터를 데이터베이스로 강제 이동하거나, 애플리케이션을 탐색할 필요 없이 전체 UI를 한눈에 보고 개발할 수 있다.
Storybook은 재사용성을 확대하기 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화하여 시뮬레이션할 수 있는 다양한 테스트 상태를 확인할 수 있다. 이를 통해 버그를 사전에 방지할 수 있도록 도와준다. 또한 테스트 및 개발 속도를 향상시키는 장점이 있으며, 애플리케이션 또한 의존성을 걱정하지 않고 빌드할 수 있다.
Storybook은 기본적으로 독립적인 개발 환경에서 실행된다. 개발자는 애플리케이션의 다양한 상황에 구애받지 않고 UI 컴포넌트를 집중적으로 개발할 수 있다.
아래 예시처럼 회사의 내부 개발자들을 위해 문서화(documentation)를 하여 회사의 UI 라이브러리로써 사용하거나, 외부 공개용 디자인 시스템(Design System)을 개발하기 위한 기본 플랫폼으로 사용할 수 있다.
Storybook에서 지원하는 주요 기능은 다음과 같다.
- UI 컴포넌트들을 카탈로그화하기
- 컴포넌트 변화를 Stories로 저장하기
- 핫 모듈 재 로딩과 같은 개발 툴 경험을 제공하기
- 리액트를 포함한 다양한 뷰 레이어 지원하기
튜토리얼
우선 Create React App을 활용해서 리액트 프로젝트를 만들어주자.
npx create-react-app storybook-practice
폴더가 생성되면, 폴더 안에서 다음 명령어를 입력하여 Storybook을 설치한다.
npx storybook init
이 명령어는 package.json 을 보고 사용 중인 프론트엔드 라이브러리에 맞는 Storybook 사용 환경을 알아서 만들어주기 때문에, 꼭 React가 아니더라도 다양한 프론트엔드 라이브러리에서 사용할 수 있다.
Storybook 설치가 완료되면, /.storybook 폴더와 /src/stories 폴더가 생성된 것을 확인할 수 있다. /.storybook 폴더에는 Storybook 관련 설정 파일이, /src/stories 폴더에는 Storybook 예시 파일들이 들어있다.
이제 터미널 창에 다음 명령어를 입력하여 Storybook을 실행한다.
npm run storybook
명령어를 입력하면 React가 localhost:3000으로 접근하듯이, localhost:6006으로 접근하여 Storybook을 실행시킨다.
Storybook을 실행하면 /src/stories 폴더 안에 있던, Storybook에서 만들어놓은 예시 스토리를 확인할 수 있다. 이렇게 Storybook을 사용하면 애플리케이션을 실행하고 이벤트를 통해 상태를 변경하는 과정을 거치지 않아도 상태 변화에 따른 컴포넌트의 변화를 확인할 수 있다.
src 폴더 안에 Title.js 파일을 하나 만들고, 다음과 같은 간단한 React 컴포넌트를 하나 만들어 export 해준다.
import React from "react";
// title은 h1 요소의 textContent, textColor은 글자색이 되는 props입니다.
const Title = ({title, textColor}) => (
<h1 style={{color: textColor}}>{title}</h1>
);
export default Title;
그리고 같은 위치인 src 폴더 안에 Title.stories.js 파일을 하나 만든다. /.storybook 안에 있는 Storybook 설정 파일에 의해서 컴포넌트 파일과 똑같은 파일 이름에 .stories를 붙여 파일을 만들면 알아서 스토리로 인식한다.
// 앞에서 작성한 컴포넌트를 불러옵니다.
import Title from "./Title";
// title : 컴포넌트 이름으로, '/'를 넣어 카테고리화 할 수 있습니다.
// 이후 예시에서 조금 더 자세히 설명합니다.
// component : 어떤 컴포넌트를 가져와서 스토리로 만들 것인지 명시합니다.
// argTypes : 컴포넌트에 필요한 전달인자의 종류와 타입을 정해줍니다.
// 지금은 title, textColor이라는 전달인자에 text 타입이 필요함을 의미합니다.
export default {
title: "Practice/Title",
component: Title,
argTypes: {
title: { control: "text" },
textColor: {control: "text"}
}
}
// 템플릿을 만들어줍니다. 이 템플릿에서는
// Title 컴포넌트가 args를 전달받아 props로 내려줍니다.
// Template은 스토리북에서 스토리 찍어낼 때 쓰는 규칙 같은 느낌(?)
const Template = (args) => <Title {...args} />
// Storybook에서 확인하고 싶은 컴포넌트는 export const로 작성합니다.
// 템플릿을 사용하여 Storybook에 넣어줄 스토리를 하나 만들어주었습니다.
// Template.bins({}); 는 정해진 문법이라고 생각하고 사용하시면 됩니다.
export const RedTitle = Template.bind({});
// 만들어준 스토리의 전달인자를 작성해줍니다.
RedTitle.args= {
title: "Red Title",
textColor: "red"
}
// 스토리를 하나 더 만듭니다.
export const BlueTitle = Template.bind({});
// 스토리의 전달인자를 작성해줍니다.
BlueTitle.args= {
title: "Blue Title",
textColor: "blue"
}
- title: “Practice/Title” 로 작성해준 코드가 좌측 메뉴에서 카테고리로 적용된 것을 확인할 수 있다. 이렇게 Practice라는 카테고리에 Title 외의 스토리도 담아줄 수 있다.
- title.stories.js 안에서 템플릿을 사용해 만든 두 개의 스토리가 Title 안에 들어있는 것을 볼 수 있다. 각 스토리에서는 작성해준 전달인자도 확인할 수 있고, 전달인자에 따라 결과물이 달라진 것도 볼 수 있다.
이번에는 전달인자를 직접 받는 스토리를 만들어보자. 앞서 만들었던 두 스토리 바로 밑에 다음과 같은 스토리를 하나 더 작성해준다.
// 전달인자를 직접 받는 스토리
export const StorybookTitle = (args) => <Title {...args} />
이번에 만든 스토리는 전달 인자를 직접 작성해주면 거기에 맞춰 모습이 변하는 것을 볼 수 있다.
이번에는 전달 인자를 직접 받으면서, Styled Components를 사용해서 만든 컴포넌트를 스토리로 만들어보자. 우선, Button.js라는 파일을 하나 만들고 다음과 같은 컴포넌트를 작성한다.
import React from "react";
import styled from "styled-components";
const StyledButton = styled.button`
background: ${(props) => props.color || "white"};
width: ${(props) => (props.size === "big" ? "200px" : "100px")};
height: ${(props) => (props.size === "big" ? "80px" : "40px")};
`
const Button = ({color, size, text}) => (
<StyledButton color={color} size={size} >{text}</StyledButton>
);
export default Button
Button.stories.js는 다음과 같이 작성해준다.
// 컴포넌트를 불러옵니다.
import Button from "./Button";
export default {
title: "Practice/Button",
component: Button,
// 이번에 작성한 전달인자의 타입은 Storybook을 보고 직접 확인해보세요.
argTypes: {
color: { control: 'color'},
size: { control: { type:'radio', options : ['big', 'small'] }},
text: { control: 'text'}
}
};
export const StorybookButton = (args) => <Button {...args}></Button>
3. useRef
JavaScript 를 사용 할 때에는, 우리가 특정 DOM 을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM 을 선택한다.
리액트를 사용하는 프로젝트에서도 가끔씩 DOM 을 직접 선택해야 하는 상황이 발생 할 때도 있다. 예를 들어서 특정 엘리먼트의 크기를 가져와야 한다던지, 스크롤바 위치를 가져오거나 설정해야 된다던지, 또는 포커스를 설정해줘야 된다던지 등 정말 다양한 상황이 있다. 추가적으로 Video.js, JWPlayer 같은 HTML5 Video 관련 라이브러리, 또는 D3, chart.js 같은 그래프 관련 라이브러리 등의 외부 라이브러리를 사용해야 할 때에도 특정 DOM 에 적용하기 때문에 DOM 을 선택해야 하는 상황이 발생할 수 있다.
그럴 땐, 리액트에서 ref 라는 것을 사용한다. 함수형 컴포넌트에서 ref 를 사용 할 때에는 useRef 라는 Hook 함수를 사용한다.
const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
<div>
<input ref={주소값을_담는_그릇} type="text" />
{/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
{/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
{/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
</div>);
이 주소값은 컴포넌트가 re-render 되더라도 바뀌지 않는다. 이 특성을 활용하여 아래의 제한된 상황에서 useRef 를 활용할 수 있다.
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>);
}
예제 1: focus()
import React, { useRef } from "react";
const Focus = () => {
const firstRef = useRef(null);
const secondRef = useRef(null);
const thirdRef = useRef(null);
const handleInput = (event) => {
console.log(event.key, event);
if (event.key === "Enter") {
if (event.target === firstRef.current) {
secondRef.current.focus();
event.target.value = "";
} else if (event.target === secondRef.current) {
thirdRef.current.focus();
event.target.value = "";
} else if (event.target === thirdRef.current) {
firstRef.current.focus();
event.target.value = "";
} else {
return;
}
}
};
return (
<div>
<h1>타자연습</h1>
<h3>각 단어를 바르게 입력하고 엔터를 누르세요.</h3>
<div>
<label>hello </label>
<input ref={firstRef} onKeyUp={handleInput} />
</div>
<div>
<label>world </label>
<input ref={secondRef} onKeyUp={handleInput} />
</div>
<div>
<label>codestates </label>
<input ref={thirdRef} onKeyUp={handleInput} />
</div>
</div>
);
};
export default Focus;
예제 2: video player
import { useRef } from "react";
export default function App() {
const videoRef = useRef(null);
const playVideo = () => {
videoRef.current.play();
console.log(videoRef.current);
};
const pauseVideo = () => {
videoRef.current.pause();
videoRef.current.remove();
};
return (
<div className="App">
<div>
<button onClick={playVideo}>Play</button>
<button onClick={pauseVideo}>Pause</button>
</div>
<video ref={videoRef} width="320" height="240" controls>
<source
type="video/mp4"
src="https://player.vimeo.com/external/544643152.sd.mp4?s=7dbf132a4774254dde51f4f9baabbd92f6941282&profile_id=165"
/>
</video>
</div>
);
}
'코드스테이츠 SEB FE 41기 > Section 별 내용 정리' 카테고리의 다른 글
section3/Unit4/ [React] 상태 관리(11/1) (0) | 2022.11.01 |
---|---|
section3/Unit3/ [React] Custom Component(10/28) (0) | 2022.10.28 |
section3/Unit2/ [사용자 친화 웹] UI/UX(10/26) (0) | 2022.10.26 |
section3/Unit2/ [사용자 친화 웹] UI/UX(10/25) (0) | 2022.10.25 |
section3/Unit2/ [사용자 친화 웹] UI/UX(10/24) (0) | 2022.10.24 |