교육 69일차 강의

구성본·2022년 6월 27일

1. 학습한 내용

React

  • react 실습
    -cmd 명령프롬프트(관리자권한 실행)
    ->cd..(나가기) -> cd React(리액트 파일로 들어가기)
    ->npx -create-react-app 프로젝트이름
    ->code .으로 프로젝트 열기
    ->npm start로 프로그램 실행

  • component => JSX(javascript + XML)
    -하나의 파일에 자바스크립트와 HTML을 동시에 자성
    -재사용이 가능하고, 코드를 작은 규모로 관리할 수 있다
    -생산성과 유지보수가 용이한 특징

-복합하고 동적인 웹어플리케이션에서 ui를 동적으로 나타내기 위해 많은 상태를 관리해야하는 부담이 생기는데 react가 이것을 해결해준다

  • react의 특징 => 선언적 방식
    -프로그램이 어떤 방법으로 해야하는 지를 나타내기보다 무엇과 같은지를 설명하는 경우 선언형 방식이라고 한다
    -리액트는 선언형 방식으로 작성

  • 컴포넌트 만들기
    -파일 확장자는 js, 컴포넌트는 단순 자바스크립트 함수
    -컴포넌트 이름은 대문자로 시작해야함, html 코드를 리턴함
    -반드시 하나의 루트 요소만 가져야 한다
    -export를 이용하여 다른 파일로 내보내야됨 (ex) App.js)

  • props
    -props를 이용하여 데이터를 컴포넌트 맞춤으로 보낼 수 있다
    -컴포넌트사이 데이터를 전달할 수 있는 방법

1. (실습) 버튼 클릭시 숫자 증가/감소

import './App.css';
import {useState} from "react"; //상태관리 함수 추가

function App() {
  // let counter = 0; 기존 방법으로 값을 변경, 리액트에서 사용X
  // counter = counter + 1; 기존 방법으로 값을 변경, 리액트에서 사용X
  
  const [counter, setCounter] = useState(0);
  const increase =()=>{
    setCounter(counter + 1);
  };

  const decrease =()=>{
    setCounter(counter - 1);
  };

  return (
    <div>
      <div>{counter}</div>
      <button onClick={increase}>증가 버튼</button>
      <button onClick={decrease}>감소 버튼</button>
    </div>
  );
}
export default App;

2. (실습) 에어비앤비 디자인 시스템 따라하기

  • 스토리북(Storybook) : UI컴포넌트 개발 도구

  • 데모용 코드를 작성하는 데 도움을 주고 공통적으로 사용될 컴포넌트를 팀원들과 편리하게 공유하는 도구로 활용

  • 구성단위는 스토리(Story)

  • 하나의 UI컴포넌트는 보통 하나 이상의 Story를 가짐

  • 장점
    -복잡한 로직 없이 독립적인 환경에서 컴포넌트를 개발할 수 있다
    -재사용을 위한 컴포넌트들을 story에서 조합해 테스트할 수 있다
    -컴포넌트들을 문서화 할 수도 있고 디자인 시스템에 적용해 피그마의 컴포넌트들과 동기화할 수 있다

  • npx -p storybook sb init 프로젝트이름 => 스토리북 프로젝트 생성

  • npm run storybook => 스토리북 프로젝트 시작

  • main.js : stories를 위한 config 설정

  • preview.js : 모든 story들에 글로벌하게 적용될 포맷 세팅

  • 스토리 기본구조

Export default {
Title : 스토리북에 올릴 component 폴더 계층 구조,
Component : 스토리를 만들 컴포넌트 이름
}
Export const 스토리이름 = () => 해당스토리에서 테스트할 인자가 담긴 컴
포넌트
  • Text 프로젝트
    -Text.jsx

import React, { Component } from 'react';
import PropTypes from "prop-types";

export function Text({children, color, italic, underline}){
    const style={
        color : color,
        fontStyle : italic? "italic" : "normal",
        textDecoration : underline? "underline" : "none",
    };
    return<span style={style}>{children}</span>;
};

Text.PropTypes = {
    children : PropTypes.string.isRequired,
    color : PropTypes.string,
    italic : PropTypes.bool,
    underline : PropTypes.bool,
};

Text.defaultProps = {
    color : "black",
    italic : false,
    underline : false,
};

-Text.stories.js

import React, { Component } from 'react';
import { Text } from './Text';

export default{
    title : "Text",
    component : Text,
};

const TEST_TEXT = "Story Text Test";
export const Default = ()=><Text>{TEST_TEXT}</Text>;
export const Red = ()=><Text color="red">{TEST_TEXT}</Text>;
export const Italic = ()=><Text italic>{TEST_TEXT}</Text>;
export const Underline = ()=><Text underline>{TEST_TEXT}</Text>;
  • Input 프로젝트
    -Input.jsx

import React, { Component } from 'react';
import PropTypes from "prop-types";

class Input extends Component{
    constructor(props){
        super(props);
        this.setRef = this.setRef.bind(this);
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(e){
        const{name, onChange} = this.props;
        if(onchange){
            onChange(name, e.target.value);
        }
    }

    componentDidMount(){
        if(this.props.autoFocus){
            this.ref.focus();
        }
    }

    componentDidUpdate(){
        if(this.props.autoFocus){
            this.ref.focus();
        }
    }

    setRef(ref){
        this.ref = ref;
    }

    render(){
        const {errorMessage, label, name, value, type, onFocus} = this.props;
        return(
            <label>
                {label}
                <input>
                    id = {"input_${name}"}
                    ref = {this.setRef}
                    onChange = {this.handleChange}
                    onFocus = {onFocus}
                    value = {value}
                    type = {type}
                </input>
                {errorMessage && <span className="error">{errorMessage}</span>}
            </label>
        );
    }
}

Input.PropTypes = {
    type: PropTypes.oneOf(["text", "number", "price"]),
    name: PropTypes.string.isRequired,
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
    errorMessage: PropTypes.string,
    label: PropTypes.string,
    onChange: PropTypes.func,
    autoFocus: PropTypes.bool,
}

Input.defaultProps = {
    onChange: () => {},
    onFocus: () => {},
    autoFocus: false,
    type: "Text",
}
export default Input;
  • ref
    -실제 dom요소에 접근하여 그것들로 작업할 수 있도록 해주는 것
    -하지만 dom의 요소들을 변경하는 것은 지양해야한다.
    -보통은 값을 빠르게 읽어오고 싶을 때 사용

-Input.stories.js

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

export default{
    title: "Input",
    component : Input,
}

export const Label = ()=><input name="name" label="이름: "/>;

2.학습한 내용 중 어려웠던 점

현재 어플리케이션을 통한 실행방법보다 리액트의 다양한 프레임워크들을 통해 작업들이 이루어지는 추세라는 걸 알았기 때문에 리액트를 공부하는 부분이 중요하다는 걸 알았다. 특히 PWA라는 프레임워크는 어플리케이션 없이 어플리케이션에서 가능한 많은 부분들을 실행 가능하게 해준다는 점에서 아주 효용성이 크다고 들었기 때문에 이런부분들이 중요하다고 생각되었다. 하지만 구동하는 부분까지 따라는 갈 수 있었지만 문ㅂ접이라던가 어떻게,왜에 대해서는 너무나도 부족한 걸 알았다. 그저 따라가기 급급한 부분들이 많기 때문에 개선할 필요가 있다.

3.해결방법

여러가지 실스부분들이나 잘 모르겠는 부분, 리액트의 활용법들을 찾아보고 물어보고 사용해봐야 한다. 지극히 간단한 구동방식을 실험해보는데도 아직은 힘겨워하기 때문에 많이 해 볼 수 밖에 없다. 시간이 많이 남지 않았음을 이해하고 시간을 계속 더 투자할 필요가 있다.

4. 학습소감

이제 2달의 시간이 남았다. 내가 뭐라도 할 수 있나라는 부분에 대해서 냉정하게 생각해볼 필요가 있다. 내가 가고싶은 가야만할 방향에 대해서는 생각해본 부분들이 있기때문에 시간을 쏟을 필요가 있다. 앞으로도 계속 배워야 하겠지만 편안한 환경에서 배울 수 있는 시간은 많지 않다. 시간을 잘 활용하자.

profile
코딩공부중

0개의 댓글