프론트엔드/React

리액트 기초이론 5 - 컴포넌트 스타일링

syleemomo 2021. 10. 22. 11:18
728x90

 

* 컴포넌트 스타일링하는 몇가지 방법

기본적으로 CSS 를 사용하여 스타일링한다. 그 밖에 SASS 와 Styled Component 가 있다. SASS 는 CSS 를 마치 프로그래밍적으로 생각하여 중복되는 CSS 코드를 변수나 함수로 만들어 사용가능하다. Styled Component 는 Tagged Template literal 을 사용하여 자바스크립트로 스타일링한다. 

컴포넌트 스타일링을 할때 어떤 도구를 사용할지를 결정하는건 개발자의 선호에 달려있다. 그보다 중요한건 어떤 도구를 사용하든 컴포넌트를 만들고 스타일링할 수 있는지다. 그래서 일단은 기본적인 CSS 를 사용하여 스타일링하는 연습을 하는 것이 우선이다. 

 

* 컴포넌트 스타일링시 참고할 문서

https://mui.com/material-ui/react-modal/

 

React Modal component - Material UI

The modal component provides a solid foundation for creating dialogs, popovers, lightboxes, or whatever else.

mui.com

Material UI 는 웹사이트 디자인을 위한 CSS 프레임워크이다. 필요한 디자인과 기능을 컴포넌트 단위로 가져다 쓸 수 있다. 해당 문서에서 Components 를 보면 리액트 컴포넌트를 구현할때 어떤 형태로 구현해야 할지 감을 잡을수 있다.

 

* 컴포넌트 스타일링의 예시

Button 컴포넌트

import React from 'react'

function Button({ children }){
    const style = {
        all: 'unset',
        color: 'white',
        background: 'tomato',
        cursor: 'pointer',
        height: '50px',
        paddingLeft: '10px',
        paddingRight: '10px',
        borderRadius: '5px',
        fontWeight: 'bold',
    }
    return <button style={style}>{children}</button>
}

export default Button;

Button.js 파일에 위 코드를 작성하자! 

import './App.css';
import Button from './Button';

function App() {
  return (
    <div className="App">
     <Button>Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일에서 Button 컴포넌트를 불러와서 사용한다. 

리액트에서는 HTML 과 같이 인라인으로 스타일을 설정할 수 있다. style 속성에 객체 형태로 스타일을 주입하면 된다. 하지만 이 방법은 간단한 테스트에는 유용하지만 분명한 한계점이 존재하고 스타일 코드와 컴포넌트 로직이 하나의 파일 안에 섞여 있기 때문에 유지보수에 좋지 않다. 

import React from 'react'
import './Button.css'

function Button({ children }){
    return <button className="Button">{children}</button>
}

export default Button;

Button.js 파일을 위와 같이 수정한다. button 에 style 속성 대신 className 을 설정하였다. Button.css 라는 스타일 관련 파일을 임포트하여 스타일을 적용한다. 

.Button {
    all: unset;
    color: white;
    background: tomato;
    cursor: pointer;
    height: 50px;
    padding-left: 10px;
    padding-right: 10px;
    border-radius: 5px;
    font-weight: bold;
}
.Button:hover{
    background: orangered;
    opacity: 0.7;
}

Button.css 파일을 생성하고 위와 같이 작성하자! 이렇게 하면 스타일 관련 코드와 컴포넌트 로직을 분리할 수 있어서 유지보수와 코드 가독성에 도움이 된다. 

만약 버튼 사이즈를 설정하려면 어떻게 하면 될까?

import React from 'react'
import './Button.css'

function Button({ children, size }){
    return <button className={`Button ${size}`}>{children}</button>
}

export default Button;

Button.defaultProps = {
    size: 'medium'
}

Button.js 를 위와 같이 수정하자! props 속성에 size 를 추가한다. className 속성에는 템플릿 리터럴을 사용하여 class 이름을 연결하고 size 변수를 주입한다. 이렇게 하면 props 로 전달되는 size 값에 따라 서로 다른 크기의 버튼 스타일을 적용할 수 있다. defaultProps 를 사용하여 size 값이 존재하지 않으면 버튼의 기본 크기는 medium 으로 설정한다. 

.Button {
    all: unset;
    color: white;
    background: tomato;
    cursor: pointer;
    border-radius: 5px;
    font-weight: bold;
    margin-left: 10px;
}
.Button:hover{
    background: orangered;
    opacity: 0.7;
}

.large{
    height: 70px;
    padding-left: 15px;
    padding-right: 15px;
    font-size: 1.2rem;
}
.medium{
    height: 50px;
    padding-left: 10px;
    padding-right: 10px;
    font-size: 1rem;
}
.small{
    height: 30px;
    padding-left: 5px;
    padding-right: 5px;
    font-size: 0.8rem;
}

Button.css 파일에 위와 같이 size 관련 스타일 코드를 추가하자! size 값에 따라 버튼의 높이, padding, 폰트크기를 다르게 설정하였다. 

import './App.css';
import Button from './Button';

function App() {
  return (
    <div className="App">
     <Button size="small">Add Todo</Button>
     <Button size="medium">Add Todo</Button>
     <Button size="large">Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일에서 다양한 크기의 버튼 컴포넌트를 사용해보자. 리액트의 컴포넌트 재사용이 바로 이런 것이다. 

다양한 크기의 버튼 컴포넌트

 

만약 버튼의 배경색을 설정하려면 어떻게 하면 될까?

import React from 'react'
import './Button.css'

function Button({ children, size, color }){
    return <button className={`Button ${size} ${color}`}>{children}</button>
}

export default Button;

Button.defaultProps = {
    size: 'medium',
    color: 'tomato'
}

Button.js 을 위와 같이 수정하자! props 로 color 속성을 추가한다. 또한, className 속성에도 color 속성을 연결한다. defaultProps 에는 props 로 전달된 color 값이 존재하지 않으면 버튼의 기본 배경색을 tomato 로 설정한다.

.Button {
    all: unset;
    color: white;
    cursor: pointer;
    border-radius: 5px;
    font-weight: bold;
    margin-left: 10px;
}
.Button:hover{
    opacity: 0.7;
}

/* 버튼의 크기 설정 */
.large{
    height: 70px;
    padding-left: 15px;
    padding-right: 15px;
    font-size: 1.2rem;
}
.medium{
    height: 50px;
    padding-left: 10px;
    padding-right: 10px;
    font-size: 1rem;
}
.small{
    height: 30px;
    padding-left: 5px;
    padding-right: 5px;
    font-size: 0.8rem;
}

/* 버튼의 배경색 설정 */
.blue{
    background:blue;
}
.blue:hover{
    background: skyblue;
}
.tomato{
    background: tomato;
}
.tomato:hover{
    background: lightsalmon;
}
.grey{
    background: grey;
}
.grey:hover{
    background: lightgray;
}

Button.css 파일에 버튼의 배경색 설정과 관련된 코드를 추가하자! 파란색과 회색 버튼을 추가하였다. 

import './App.css';
import Button from './Button';

function App() {
  return (
    <div className="App">
     <Button size="small" color="blue">Add Todo</Button>
     <Button size="medium" color="tomato">Add Todo</Button>
     <Button size="large" color="grey">Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 수정하자! Button 컴포넌트의 props 로 color 속성을 추가한다. 

다양한 배경색의 버튼 컴포넌트

 

만약 버튼이 전체 너비를 다 차지하도록 하려면 어떻게 하면 될까?

import React from 'react'
import './Button.css'

function Button({ children, size, color, width }){
    return <button className={`Button ${size} ${color} ${width}`}>{children}</button>
}

export default Button;

Button.defaultProps = {
    size: 'medium',
    color: 'tomato',
}

Button.js 파일을 위와 같이 수정하자! props 로 width 옵션을 추가한다. 

.Button {
    all: unset;
    color: white;
    cursor: pointer;
    border-radius: 5px;
    font-weight: bold;
    margin-left: 10px;
    text-align: center;
}
.Button:hover{
    opacity: 0.7;
}

/* 버튼의 크기 설정 */
.large{
    height: 70px;
    padding-left: 15px;
    padding-right: 15px;
    font-size: 1.2rem;
}
.medium{
    height: 50px;
    padding-left: 10px;
    padding-right: 10px;
    font-size: 1rem;
}
.small{
    height: 30px;
    padding-left: 5px;
    padding-right: 5px;
    font-size: 0.8rem;
}

/* 버튼의 배경색 설정 */
.blue{
    background:blue;
}
.blue:hover{
    background: skyblue;
}
.tomato{
    background: tomato;
}
.tomato:hover{
    background: lightsalmon;
}
.grey{
    background: grey;
}
.grey:hover{
    background: lightgray;
}
/* 전체 너비를 차지하는 버튼 */
.fullWidth{
    width: 100%;
    margin-left: 0px;
    margin-top: 10px;
    margin-bottom: 10px;
}

Button.css 파일을 위와 같이 수정하자! width 옵션에 fullWidth 값을 설정하면 버튼이 한 줄 전체를 차지한다.

import './App.css';
import Button from './Button';

function App() {
  return (
    <div className="App">
     <Button size="small" color="blue" >Add Todo</Button>
     <Button size="medium" color="tomato" width="fullWidth">Add Todo</Button>
     <Button size="large" color="grey">Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 수정하자! 두번째 버튼에 props 로 width 옵션을 설정한다. 

전체 너비를 차지하는 버튼 컴포넌트

 

만약 버튼을 클릭했을때 어떠한 동작을 수행하게 하려면 어떻게 하면 될까?

import React from 'react'
import './Button.css'

function Button({ children, size, color, width, handleClick }){
    return <button 
                className={`Button ${size} ${color} ${width}`} 
                onClick={handleClick}
            >{children}</button>
}

export default Button;

Button.defaultProps = {
    size: 'medium',
    color: 'tomato',
}

Button.js 파일을 위와 같이 수정하자! props 에 handleClick 을 추가한다. 그리고 button 요소에 onClick 을 설정하여 버튼 컴포넌트가 클릭되었을때 props 로 전달된 handleClick 함수가 실행되도록 한다. 

import './App.css';
import Button from './Button';

function App() {
  const handleClick = () => alert('clicked button') // 이벤트핸들러 함수
  return (
    <div className="App">
     <Button size="small" color="blue" handleClick={handleClick}>Add Todo</Button>
     <Button size="medium" color="tomato" width="fullWidth">Add Todo</Button>
     <Button size="large" color="grey">Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 수정하자! 간단한 이벤트핸들러 함수를 추가한다. 그리고 첫번째 버튼의 props 로 handleClick 을 설정한다. 이렇게 하면 이벤트핸들러 함수가 Button 내부로 전달되어 버튼 컴포넌트가 클릭될때 실행된다.

첫번째 버튼 컴포넌트를 클릭한 모습

 

만약 버튼을 비활성화하여 버튼을 클릭해도 동작하지 않게 하려면 어떻게 하면 될까?

import React from 'react'
import './Button.css'

function Button({ children, size, color, width, handleClick, disabled }){
    return <button className={`Button ${size} ${color} ${width} ${disabled ? 'blocked' : ''}`} onClick={handleClick} disabled={disabled}>{children}</button>
}

export default Button;

Button.defaultProps = {
  size: 'medium',
  color: 'tomato',
  disabled: false
}

Button.js 파일을 위와 같이 수정하자! props 에 disabled 속성을 추가한다. 그리고 button 요소에 disabled 속성을 전달받은 props 로 설정한다. defaultProps 에 disabled 값을 false 로 설정하여 기본적으로 버튼이 활성화되도록 설정한다. 또한, 클래스 이름에 disabled props 가 true 인 경우 blocked 라는 스타일이 적용되도록 한다. 

.Button {
  all: unset;
  color: white;
  cursor: pointer;
  border-radius: 5px;
  font-weight: bold;
  margin-left: 10px;
  text-align: center;
}
.Button:hover{
  background: orangered;
  opacity: 0.7;
}

.large{
  height: 70px;
  padding-left: 15px;
  padding-right: 15px;
  font-size: 1.2rem;
}
.medium{
  height: 50px;
  padding-left: 10px;
  padding-right: 10px;
  font-size: 1rem;
}
.small{
  height: 30px;
  padding-left: 5px;
  padding-right: 5px;
  font-size: 0.8rem;
}

/* 버튼의 배경색 설정 */
.blue{
  background:blue;
}
.blue:hover{
  background: skyblue;
}
.tomato{
  background: tomato;
}
.tomato:hover{
  background: lightsalmon;
}
.grey{
  background: grey;
}
.grey:hover{
  background: lightgray;
}

/* 전체 너비를 차지하는 버튼 */
.fullWidth{
  width: 100%;
  margin-left: 0px;
  margin-top: 10px;
  margin-bottom: 10px;
}

/* 비활성화 버튼 */
.blocked{
  background: lightgray;
  text-decoration: line-through;
}
.blocked:hover{
  background: lightgray;
  opacity: 1;
}

Button.css 파일을 위와 같이 수정하자! 비활성화 버튼에 관련된 스타일 코드를 추가한다. 

import './App.css';
import Button from './Button';

function App() {
  const handleClick = () => alert('clicked button') // 이벤트핸들러 함수
  return (
    <div className="App">
     <Button size="small" color="blue" handleClick={handleClick} disabled={true}>Add Todo</Button>
     <Button size="medium" color="tomato" width="fullWidth">Add Todo</Button>
     <Button size="large" color="grey">Add Todo</Button>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 수정하자! 첫번째 버튼에 disabled 속성을 true 로 설정하면 버튼이 비활성화되어 클릭해도 alert 창이 뜨지 않음을 확인할 수 있다. 

만약 버튼에 아이콘을 넣으려면 어떻게 하면 될까?

import './App.css';
import Button from './Button';

function App() {
  const handleClick = () => alert('clicked button') // 이벤트핸들러 함수
  return (
    <div className="App">
     <Button size="small" color="blue" handleClick={handleClick} disabled={true}>Add Todo</Button>
     <Button size="medium" color="tomato">
       <img src="http://simpleicon.com/wp-content/uploads/rocket.png" width="30px" height="30px"></img>
       Add Todo
     </Button>
     <Button size="large" color="grey">Add todo</Button>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 수정하자! 두번째 버튼에 아이콘을 추가하였다. Button 컴포넌트의 children (컨텐츠)으로 img 요소를 추가하여 아이콘을 보여줄 수 있도록 하였다. 

.Button {
    all: unset;
    color: white;
    cursor: pointer;
    border-radius: 5px;
    font-weight: bold;
    margin-left: 10px;
    text-align: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

Button.css 파일에서 .Button 선택자에 flex 속성을 추가하였다. 이렇게 한 이유는 버튼 컴포넌트 내부의 아이콘과 글자를 정렬하기 위함이다. 

.App{
  display: flex;
  align-items: center;
  justify-content: center;
}

마지막으로 App.css 파일에 위와 같이 작성하여 버튼을 브라우저 화면 중앙에 정렬한다. 

아이콘이 추가된 최종 버튼

 

 

Modal 컴포넌트

import React from 'react'
import './Modal.css'

function Modal({ open, children }){
    return <div className={`Modal ${open? "open": "close"}`}>{children}</div>
}

export default Modal;

Modal.defaultProps = {
    open: false
}

Modal.js 파일을 생성하고 위 코드를 작성하자! props 로 open 과 children 을 전달받는다. 삼항연산자를 사용하여 open 의 상태에 따라 모달창을 열거나 닫도록 스타일을 설정한다. defaultProps 를 설정하여 기본적으로 모달창이 보이지 않도록 한다. 

.Modal {
  width: 500px;
  padding: 10px;
  text-align: center;
  box-shadow: 1px 1px 5px 1px tan;
  background: white;
  z-index: 1;
  position: fixed;
  overflow: hidden;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.open{
  display: block;
}
.close{
  display: none;
}

Modal.css 파일을 생성하고 위 코드를 작성하자! 

import './App.css';
import Modal from './Modal';

function App() {
  return (
    <div className="App">
      <Modal open={true}>Modal contents</Modal>
    </div>
  );
}

export default App;

App.js 파일을 위와 같이 작성하자! Modal 컴포넌트를 임포트하여 사용하였다. open 속성에 true 를 전달하여 모달창이 열리도록 하였다. 

모달창이 열린 모습

 

만약 버튼을 클릭했을때 모달창이 열리게 하려면 어떻게 하면 될까?

import './App.css';
import Modal from './Modal';
import Button from './Button';
import { Component } from 'react';

class App extends Component {
  state = {
    open: false
  }
  openModal = () => {
    this.setState({ open: true })
  }
  render(){
    const { open } = this.state
    return (
      <div className="App">
        <Button handleClick={this.openModal}>Open Modal window</Button>
        <Modal open={open}>Modal contents</Modal>
      </div>
    );
  }
}

export default App;

App.js 파일을 위와 같이 수정하자! state 를 사용하기 위하여 App 컴포넌트를 함수형에서 클래스형으로 전환하였다. 이전에 만들어둔 버튼 컴포넌트를 임포트하고 handleClick 속성에 openModal 이라는 이벤트핸들러 함수를 설정하였다. 이렇게 하면 버튼이 클릭되었을때 openModal 이벤트핸들러가 실행되면서 open 상태를 true 로 변경하고 모달창이 열리게 된다. 

버튼 클릭시 모달창이 열린 모습

 

모달창 컨텐츠로 좀 더 실용적인 내용을 전달해보자.

import './App.css';
import Modal from './Modal';
import Button from './Button';
import { Component } from 'react';

class App extends Component {
  state = {
    open: false
  }
  openModal = () => {
    this.setState({ open: true })
  }
  render(){
    const { open } = this.state
    return (
      <div className="App">
        <Button handleClick={this.openModal}>Open Modal window</Button>
        <Modal open={open}>
          <div className="Modal-header">Modal header</div>
          <div className="Modal-body">Modal body</div>
          <div className="Modal-footer">Modal footer</div>
        </Modal>
      </div>
    );
  }
}

export default App;

App.js 파일을 위와 같이 수정하자! Modal 은 기본적으로 header, body, footer 로 구성된다. header 에는 사용자에게 전달할 안내 메세지를 주로 보여준다. body 에는 사용자 입력을 받기 위한 input 요소나 긴 문장의 안내문구가 보여진다. footer 에는 주로 사용자 인터렉션을 위한 버튼이 위치한다.

.Modal {
  width: 500px;
  padding: 10px;
  text-align: center;
  box-shadow: 1px 1px 5px 1px tan;
  background: white;
  z-index: 1;
  position: fixed;
  overflow: hidden;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.open{
  display: block;
}
.close{
  display: none;
}

.Modal-header, .Modal-body, .Modal-footer{
  padding: 5px;
}
.Modal-header{
  font-size: 1.2rem;
  font-weight: bold;
}
.Modal-body{
  font-size: 0.9rem;
}
.Modal-footer{
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

Modal.css 파일을 위와 같이 수정하자! 모달창의 header, body, footer 에 관련된 스타일을 추가하였다. 

모달창에 컨텐츠를 추가한 모습

 

이제는 모달의 컨텐츠에 좀 더 복잡하고 실용적인 내용을 주입해보자!

import './App.css';
import Modal from './Modal';
import Button from './Button';
import { Component } from 'react';

class App extends Component {
  state = {
    open: false
  }
  openModal = () => {
    this.setState({ open: true })
  }
  closeModal = () => {
    this.clearInputs()
    this.setState({ open: false })
  }
  // 인풋창 초기화
  clearInputs = () => {
    const inputs = document.querySelectorAll('.Modal-body input')
    for(let input of inputs){
      input.value = ''
    }
  }
  componentDidUpdate(){
    if(this.state.open){ // 모달창이 열려있으면 
      const firstInput = document.querySelectorAll('.Modal-body input')[0] // 첫번째 인풋창
      firstInput.focus() // 첫번째 인풋창 포커스
    }
  }
  render(){
    const { open } = this.state
    const { openModal, closeModal} = this
    return (
      <div className="App">
        <Button handleClick={openModal}>Add Todo</Button>
        <Modal open={open}>
          <div className="Modal-header">You want to add new todo ?</div>
          <div className="Modal-body">
            <label>todo name: <input type="text"></input></label><br/>
            <label>todo description: <input type="text"></input></label>
          </div>
          <div className="Modal-footer">
            <Button size="small">Add</Button>
            <Button size="small" handleClick={closeModal}>Close</Button>
          </div>
        </Modal>
      </div>
    );
  }
}

export default App;

App.js 파일을 위와 같이 수정하자! 모달창을 여는 Button 의 문구를 Add Todo 로 수정한다. 모달창 header 부분의 문구를 수정한다. body 부분에는 사용자가 새로운 할일을 추가할 수 있는 입력창을 추가한다. footer 부분에는 두개의 버튼을 추가한다. 하나는 사용자가 할일을 추가하기 위한 것이고, 나머지 하나는 모달창을 닫기 위한 것이다.

handleClick 속성에 closeModal 이라는 이벤트핸들러 함수를 설정한다. 해당 버튼을 클릭하면 closeModal 이벤트핸들러가 실행되면서 open 상태를 false 로 변경하여 모달창을 닫는다. 또한, 모달창을 닫을때 사용자가 입력한 내용을 지우고 초기화하기 위하여 clearInputs 메서드를 선언하고 closeModal 이 실행될때 내부에서 실행되도록 한다. 

.Modal {
  width: 500px;
  padding: 10px;
  text-align: center;
  box-shadow: 1px 1px 5px 1px tan;
  background: white;
  z-index: 1;
  position: fixed;
  overflow: hidden;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.open{
  display: block;
}
.close{
  display: none;
}

.Modal-header, .Modal-body, .Modal-footer{
  padding: 5px;
}
.Modal-header{
  font-size: 1.2rem;
  font-weight: bold;
}
.Modal-body{
  font-size: 0.9rem;
}
.Modal-footer{
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.Modal-body input{
  width: 60%;
  height: 30px;
  border: 1px solid lightgray;
  border-radius: 10px;
  margin-bottom: 10px;
  outline: none;
  padding-left: 7px;
  color: gray;
  font-weight: bold;
  font-size: 1.1rem;
}

Modal.css 파일을 위와 같이 수정하자!  입력창에 관련된 스타일 코드를 추가하였다. 

새로운 할일을 추가하기 위한 모달창 디자인

전체적인 모달창의 디자인은 위와 같다. Close 버튼을 클릭하면 모달창이 닫히면서 사용자가 입력한 내용이 지워진다. 

import './App.css';
import Modal from './Modal';
import Button from './Button';
import { Component } from 'react';

class App extends Component {
  state = {
    open: false
  }
  openModal = () => {
    this.setState({ open: true })
  }
  closeModal = () => {
    this.clearInputs()
    this.setState({ open: false })
  }
  // 두번째 인풋창에서 엔터키 클릭시 모달창 닫기
  handleKeyUp = (e) => {
    console.log(e.key)
    if(e.key === 'Enter'){
      this.closeModal()
    }
  }
  // 인풋창 초기화
  clearInputs = () => {
    const inputs = document.querySelectorAll('.Modal-body input')
    for(let input of inputs){
      input.value = ''
    }
  }
  componentDidUpdate(){
    if(this.state.open){ // 모달창이 열려있으면 
      const firstInput = document.querySelectorAll('.Modal-body input')[0] // 첫번째 인풋창
      firstInput.focus() // 첫번째 인풋창 포커스
    }
  }
  render(){
    const { open } = this.state
    const { openModal, closeModal, handleKeyUp} = this
    return (
      <div className="App">
        <Button handleClick={openModal}>Add Todo</Button>
        <Modal open={open}>
          <div className="Modal-header">You want to add new todo ?</div>
          <div className="Modal-body">
            <label>todo name: <input type="text"></input></label><br/>
            <label>todo description: <input type="text" onKeyUp={handleKeyUp}></input></label>
          </div>
          <div className="Modal-footer">
            <Button size="small">Add</Button>
            <Button size="small" handleClick={closeModal}>Close</Button>
          </div>
        </Modal>
      </div>
    );
  }
}

export default App;

두번째 인풋창(할일에 대한 상세정보)에서 사용자가 엔터키를 눌렀을때 모달창을 닫으려면 두번째 인풋창의 onKeyUp 이벤트에 handleKeyUp 이라는 이벤트핸들러 함수를 실행하도록 하면 된다. handleKeyUp 함수에서는 사용자가 입력한 키가 무엇인지 조회하고 'Enter' 키인 경우 closeModal 을 실행한다. 

 

* 연습과제 1

import './App.css'; 
import { Component } from 'react';
import Nav from './Nav'

class App extends Component { 
  render(){ 
    return ( 
              <div className="App"> 
                <Nav></Nav>
              </div> 
            ); 
  } 
}
   
export default App;

주어진 App 컴포넌트를 참고하여 Nav 컴포넌트를 만들어보자!

import Button from './Button'
import './Nav.css'

function Nav(){
    const navigate = (url) => {
        window.location.href = url
    }
    return (
        <div className="nav-container">
            {/* 구현하기 */}
        </div>
    )
}

export default Nav

Nav 컴포넌트는 위에서 구현한 Button 컴포넌트를 사용한다. navigate 이벤트핸들러 함수를 참고하여 버튼을 클릭했을때 아래와 같이 각 사이트로 이동할 수 있도록 구현해보자! 사전검색 서비스의 사이트 주소는 https://sssssqew.github.io/dictionary/ 이다. 

네비게이션 메뉴
사전 검색 서비스 사이트로 이동한 모습

 

 

* 연습과제 2

할일을 삭제하는 모달창&nbsp;

 

Remove 버튼을 클릭한 경우

Remove 버튼을 클릭했을때 모달창이 닫히고, 위와 같은 메세지를 화면에 보여주도록 한다. 

 

* 연습과제 3

라이프사이클 연습과제 3 의 코드를 기반으로 영단어를 보여주는 Card 컴포넌트를 따로 만들고 App 에서 임포트하여 보여주자! Card 컴포넌트 디자인은 여러분 각자가 알아서 이쁘게 하면 된다. 

영단어 암기장 앱

 

* 연습과제 4

오늘 배운 버튼 컴포넌트 예제 코드를 참고하여 아래와 같이 Input 컴포넌트를 설계해보자! (Input 컴포넌트는 size, color, label, width, handleChange, disabled, placeholder 속성에 따라 다르게 보인다.)

import './App.css';
import React, { Component } from 'react'
import Input from './Input'

function App() {
  const handleChange = () => console.log('Typing something...') // 이벤트핸들러 함수
  return (
    <div className="App">
     <Input size="small" color="blue" handleChange={handleChange} disabled={true} label="Add Todo" placeholder="Type todo to add ..."/>
     <Input size="medium" color="tomato" label="입력창" placeholder="뭐든지 입력하세요 !"/>
     <Input size="large" color="grey" label="Remove Todo" placeholder="Type todo to remove ..."/>
    </div>
  );
}

export default App;
.App {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
}

Input 컴포넌트 스타일링 결과&nbsp;

 

* 연습과제 5

https://syleemomo.tistory.com/46

 

리액트 기초이론 4 - 컴포넌트의 생명주기 (Life cycle)

생명주기 참조문서 React.Component – React A JavaScript library for building user interfaces ko.reactjs.org 생명주기 예시 State and Lifecycle – React A JavaScript library for building user interfaces ko.reactjs.org * 컴포넌트 생명주

syleemomo.tistory.com

컴포넌트 생명주기 연습과제 4번의 화장품 쇼핑몰 사이트에서 네비게이션 바에 검색창을 추가하고 검색기능을 구현해보세요!

728x90