웹개발 (2)

ppparkta·2022년 11월 8일
1

웹개발

목록 보기
3/26

오늘 학습한 내용

  • state 적응 연습 (converter 완성)
  • prop, prop-types 사용한 prop관리
  • React.memo()로 리렌더링 관리하기
  • react app 사용방법
    • react-create-app
    • 컴포넌트 분리해서 생성하기
    • 독립적인 css만들기

실습 super converter

어제 배운 내용을 바탕으로 kilometers<->miles 변환 기능을 추가해 컨버터를 완성했다. 영상 댓글에 수강생들의 작품이 종종 링크로 올라오는데, 그 중 디자인이 예쁜 작품을 참고해 css를 작성했다.

  • input에 값 입력 시 받아오기
  • 받아온 값을 kilometers와 miles에 각각 value로 설정하기
  • value 이용해서 변환기능 구현
  • boolean자료형 이용해서 스위치 구현

이런식으로 km2miles, minutes2hours 컴포넌트를 만들고 그 컴포넌트를 하나의 Container 컴포넌트에 넣었다.

구조분해할당으로 useState를 받아왔다. 이렇게 받아온 kilofilter2로 JSX를 조작한다.

const [filter2, setFilter2] = React.useState(false);
const [kilo, setKilo] = React.useState();

받아온 배열을 이용해서 이벤트 함수를 조작한다.

const onChange = (event) => {
	setKilo(event.target.value);
};
function onReset(){
    setKilo(0);
};
function onClickInvert() {
    onReset();
    setFilter2((current) => !current);
}

함수를 만들었으면 JSX의 속성에 붙여준다. 간혹 변수를 이용해서 연산하는 경우도 있는데, 그 경우에도 마찬가지로 {변수(함수)명} 형식으로 써준다.

		<div>
          <h3>km to miles</h3>
          <div>
            <lable htmlFor="killom">kilometers</lable>
            <input
              id="km"
              placeholder="km"
              type="number"
              value={filter2 ? kilo / 0.6214 : kilo}
              onChange={onChange}
              disabled={filter2}
            ></input>
          </div>
          <div>
            <lable htmlFor="miles">miles</lable>
            <input
              id="miles"
              placeholder="miles"
              type="number"
              value={filter2 ? kilo : kilo * 0.6214}
              onChange={onChange}
              disabled={!filter2}
            ></input>
          </div>
          <button onClick={onReset}>Reset</button>
          <button onClick={onClickInvert}>
            {filter2 ? `Turn back` : `Invert`}
          </button>
        </div>

코드를 완성시키고 css를 입혀줬다. css작업하면서 invert버튼을 누를 때 값이 초기화되지 않고 NaN로 뜨는 오류를 발견했다. 입력된 값이 string으로 받아들여져서 생긴 문제 같았다. JSX의 input 옵션에 type="number"를 추가하니까 문제가 해결됐다.

완성!


props

props는 properties를 줄인 말이라고 한다. 굳이 컴포넌트 함수를 만드는 이유는 코드 재사용성을 높이기 위함인데, 당연히 용도별로 내용이 달라질 수 있으니 부모 컴포넌트에게서 props를 받아와서 입맛에 맞게 수정할 수 있어야 한다.

이렇게 Btn이라는 컴포넌트와 Container라는 컴포넌트가 존재할 때, Container를 부모 컴포넌트로 볼 수 있다.

function Btn() {
        return (
          <button
            style={{
              backgroundColor: "tomato",
              color: "white",
            }}
          >
          </button>
        );
      }
function Container() {
      return (
        <div>
          <Btn banana="Save Changes" />
          <Btn banana="Continue" />
        </div>
      );
    }

props를 이용하기 위해서 Btn에 매개변수를 넣어줄 수 있다.

function Btn(props)

이런식으로 변수를 넣어주게 되면 props.~식으로 자식 컴포넌트에서 접근할 수 있다. 그런데 모든 오브젝트를 넘길 필요가 없다면 이런 식으로 선언하면 된다.

function Btn( {banana} )

오브젝트의 일부만 넘겨주는 것이다. 이러면 같은 속성에 접근하기 위해 props.banana를 쓰는 것이 아니라 banana만으로 접근할 수 있어서 사용하기 편하다. 오브젝트 속성 여러개 보내주는 것도 가능함. function Btn({banana,big}) 이런 식으로!

memo

이렇게 props를 쓰다보면 리렌더링이 많이 발생할 수 있음. 그 중에서도 리렌더링 할 필요가 없는 것들이 리렌더링 될 수 있다.

그런 상황에서 리렌더링을 방지해주는 것이 React.memo() 다. 해당 컴포넌트의 모든 리렌딩을 금지시키는게 아니라, props로 인해 변경이 일어난 부분만 변경된다.

컴포넌트가 React.memo()로 wrapping 될 때, React는 컴포넌트를 렌더링하고 결과를 메모이징(Memoizing)한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, React는 메모이징(Memoizing)된 내용을 재사용한다.

prop types

prop추가할 때 문법적인 오류가 아니라 자료형을 잘못 줬다던가 하는 문제는 컴퓨터가 잡아낼 수 없음. 그럴 때 prop의 자료형을 지정할 수 있게 도와주는게 prop types임/

아래의 소스 붙여넣으면 propTypes라는 옵션을 쓸 수 있다.

<script src="https://unpkg.com/prop-types@15.7.2/prop-types.js"></script>
Btn.propTypes = {
      text: PropTypes.string.isRequired,
      fontSize: PropTypes.number,
    };

내가 사용한걸 하나 하나 뜯어보면, Btn.propTypes 객체 안에는 내가 사용한 props의 이름과 이름에 대한 값을 넣어줄 수 있다.

여기에 PropTypes.자료형을 써주면 해당 자료형이 아닌 값이 들어왔을 때 콘솔에 경고가 난다. text: PropTypes.string.isRequired를 보면 isRequired는 모든 부모 컴포넌트에서 props를 명시해야 한다는 뜻이다.


React app

여태까지의 작업에서는 html파일에 직접 소스를 붙여넣어서 사용했었다. 이런걸 모듈을 직접 넣어주는 작업이라고 한다.

<script src="https://unpkg.com/react@17.0.2/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

그런데 매번 이런식으로 파일을 만들면 너무 복잡하다. 이틀간 작업하면서도 간단한 파일을 하나 만드는데 버전 등의 문제에 부딪혀 많은 시간을 소비했다. React app을 사용하면 위의 작업을 거치지 않아도 react로 프로그래밍을 할 수 있다.

일단 node.js 사이트에 접속해서 node.js를 다운받는다. 그리고 터미널에서 내가 파일을 만들고자 하는 경로로 들어간다.

$ node -v

node.js가 제대로 깔렸는지 확인하는 명령어다.

$ npx

npx가 뭔지 궁금해서 찾아봤는데 모듈의 일종이라고 한다. 비슷하게 npm이 있는데 업데이트가 잦은 react-create-app의 특성 상 모듈을 로컬에 저장하지 않고, 매번 최신 버전의 파일만을 임시로 불러와 실행 시킨 후에, 다시 그 파일은 없어지는 방식으로 모듈이 돌아가는 npx가 더 적합하다고 한다.

터미널에 npx를 입력하여 마찬가지로 npx명령어를 사용할 수 있는지 확인한다.

$ npx create-react-app 폴더명

이렇게 입력하면 react app으로 react폴더를 만들 수 있다. 거의 다 옴!
만들어진 폴더에 들어가서 터미널에 다음과 같이 입력한다.

$ npm start

이런 명령어를 입력하면 개발용 서버를 만들게 된다. 이 때 자동으로 페이지가 열리게 되는데, 그게 내 페이지다. 여기서는 npm을 썼다. 다시 내가 만든 폴더에 들어가면 src라는 폴더가 생성된 것을 확인할 수 있다.

실습할 때는 App.js와 index.js만 남기고 다 지워도 된다. 두 파일만 깔끔하게 남겨두면 html파일을 사용하던 환경과 유사해진다.

새로운 js파일 생성해서 가져오기

js에서 어떤 파일을 서로 가져오기 위해서 import를 사용한다.

일단 새로운 파일("button.js")을 만들고 컴포넌트를 생성했다.

function Button({text}){
	return <button>{text}</button>;
}

이렇게 만든 컴포넌트를 App에서 쓰기 위해서 하단에 아래의 코드를 추가한다.

export default Button;

App.js에서 다른 경로에 만들어진 컴포넌트를 사용하기 위해 상단에 아래의 코드를 추가한다.

import 컴포넌트명 from "컴포넌트 경로";
import Button from "./button";

react app에 prop types 가져오기

react app에서 prop types를 쓰고 싶으면 다음을 터미널에 입력하면 된다.

$ npm i prop-types

나는 오류가 났는데 prop types 실행에 지장 없어서 무시했다. 설치했으면 다시 컴포넌트를 생성한 파일로 올라와서("button.js")

import PropTypes from "prop-type";

입력하고 prop types를 설정해준다. 컴포넌트의 전체적인 모습은 아래와 같음.

import PropTypes from "prop-types";

function Button({ text }) {
  return <button>{text}</button>;
}

Button.propTypes={
	text:PropTypes.string.isRequired,
};

export default Button;

대소문자 구분 완전 헷갈린다. ㅡㅡ

react-app의 .module.css

리액트의 장점이 분할정복한다는 점인데, css도 가능하다. 단 일반적인 방법으로 css를 작성하고 import하는 것은 다를 바 없음!

import "./style.css";

이렇게 선언하면 일반적인 css 가져오게 된다. 특정 컴포넌트에만 css를 적용하고 싶을 때는 다음과 같이 하면 됨. 우선 css파일의 이름을 ~.module.css"로 바꾸고 적용하고자 하는 컴포넌트 파일에 간다.

컴포넌트명.module.css 형태로 css명을 바꾸는게 중요하다.

나는 Button.module.css로 이름을 변경했다.

css도 특정 태그를 바로 선택하는게 아니라 클래스를 만들었다.

.btn {
  color: white;
  background-color: tomato;
}
import styles from "./Button.module.css";

이렇게 import하게 되면 styles가 css 코드를 가지고 있는 객체로 넘어온다.
따라서 해당 css코드에 작성된 class name(여기서는 btn)을 프로퍼티 접근 연산자(.)를 사용해서 이용가능하다.

css로 클래스를 만들었기 때문에 이렇게 만들어진 styles객체를 jsx 옵션에 붙여주면 된다.

function Button({ text }) {
  return <button className={styles.btn}>{text}</button>;
}

만약에 여러개의 css를 각각의 컴포넌트에 styles라는 객체로 import하고 심지어 css에 만들어둔 클래스까지 겹친다고 해도 걱정하지 않아도 된다. 예를들어

import styles from "./Button.module.css";
import styles from "./Title.module.css";

이런 상황에서 각각의 컴포넌트에서 styles.btn 이런 식으로 접근한다고 해도 html에서 두 스타일을 랜덤한 값으로 생성하기 때문에 문제 생길 일이 없다.

정리해보면 css를 모듈화해서 사용하기 위해서는 다음과 같은 단계를 거쳐야 한다.

  • css이름을 컴포넌트명.module.css 로 변경하기
  • css에서 지정하는 태그를 모두 클래스로 바꾸기
  • css를 적용하고자 하는 컴포넌트에 import styles from "./컴포넌트명.module.css" 작성
  • 컴포넌트 jsx 내부에 className={styles.css클래스명} 붙이기

이렇게 만들면 css를 모듈화할 수 있다. 하나의 파일에 css를 관리하는 것보다 이런식으로 관리하는게 유지보수 쉬워보인다.

ㅡㅅㅡ 어렵다

profile
겉촉속촉

0개의 댓글