20230207 [react] - 컴포넌트 분리, 컴포넌트화

lionloopy·2023년 2월 7일
0

리액트

목록 보기
4/18

컴포넌트

:리액트 컴포넌트를 만들 땐, 함수형과 클래스형이 있고 주로 함수형을 사용한다.
리액트 컴포넌트를 만들 땐, import를 통하여 리액트를 불러와주어야 하고,
export를 통하여 다른 컴포넌트에서 불러와 사용할 수 있다.
자식은 export로 내보내고, 부모는 import로 자식을 품는다.
자식

import React from 'react';

function Hello() {
  return <div>안녕하세요</div>
}

export default Hello;

부모

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <div>
      <Hello />
    </div>
  );
}

export default App;

export로 Hello를 내보내고, import로 Hello를 가져온다.

JSX

:리액트에서 생김새를 정의할 때 사용하는 문법이다.
return 아래 작성한다.
규칙

  • 태그와 태그사이 내용이 들어가지 않을 때는 self closing
<Hello />
  • 두개 이상의 태그는 무조건 하나의 태그로 감싸져야 한다.
return(
    <div>
      <Hello />
      <div>안녕히계세요</div>
    </div>
    )
  • JSX내부에 자바스크립트 변수를 보여줘야 할 때는 { } 를 이용한다.
    <>
      <Hello />
      <div>{name}</div>
    </>

props

:프로퍼티의 줄임말. 우리가 어떠한 값을 컴포넌트에 전달해 주어야 할 때 사용한다. prop는 파라미터를 통해 전달되며, 객체 형태로 전달된다.
(파라미터 : 함수 매개변수)
(부모가 자식한테 props를 통해 전달한다.)
name의 값을 조회하고 싶다면 props.name 형태로 사용하면 된다.
App컴포넌트에서 Hello컴포넌트를 사용하면서, name이라는 값을 전달해주고 싶을 때 ▼
App.js

import React from 'react';
import Hello from './Hello';

function App() {
  return (
    <Hello name="react" />
  );
}

export default App;

Hello.js

import React from 'react';

function Hello(props) {
  return <div>안녕하세요 {props.name}</div>
}

export default Hello;

export로 Hello를 내보낸 자식, import로 Hello를 받은 부모가 있다.
부모에서 자식으로 name이라는 값을 전달하고 싶을 때,
자식은 props를 파라미터로 받고 props.name으로 찍어줄 수 있다.
props는 객체형태로 전달되기 때문에 props.name으로 찍어준다.
이렇게도 바꿀 수 있다.

import React from 'react';

function Hello(name) {
  return <div>안녕하세요 {name}</div>
}

export default Hello;

props.children

:컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 때 활용할 수 있다.
Wrapper.js로 감싸고 싶을 때 ▼
Wrapper.js => 자식

import React from 'react';

function Wrapper() {
  const style = {
    border: '2px solid black',
    padding: '16px',
  };
  return (
    <div style={style}>

    </div>
  )
}

export default Wrapper;

App.js => 부모

import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';

function App() {
  return (
    <Wrapper>
      <Hello name="react" color="red"/>
      <Hello color="pink"/>
   </Wrapper>
  );
}

export default App;

Wrapper를 받아와 원래 있던 내용을 감쌌지만, 화면상 이렇게 내용이 가려진다.

Wrapper.js

import React from 'react';

function Wrapper({ props }) {
  const style = {
    border: '2px solid black',
    padding: '16px',
  };
  return (
    <div style={style}>
      {props.children}
    </div>
  )
}

export default Wrapper;

이렇게 자식 컴포넌트에 props.children을 넣어주면 겹치지 않게 된다.

조건부 렌더링

:특정 조건에 따라 다른 결과물을 렌더링 하는 것
App.js => 부모

import React from 'react';
import Hello from './Hello';
import Wrapper from './Wrapper';


function App() {
  return (
    <Wrapper>
      <Hello name="react" color="red" isSpecial={true}/>
      <Hello color="pink" />
    </Wrapper>
  )
}

export default App;

Hello.js => 자식

import React from 'react';

function Hello({ color, name, isSpecial }) {
  return (
    <div style={{ color }}>
      { isSpecial ? <b>*</b> : null }
      안녕하세요 {name}
    </div>
  );
}

Hello.defaultProps = {
  name: '이름없음'
}

export default Hello;

export로 Hello를 내보내고, 부모는 import로 Hello를 받는다.
부모 컴포넌트에서 Hello안에 값을 넣고,
자식은 그 값들을 매개변수로 받는다. (props)
그리고 중간에 삼항연산자를 활용하여 조건에 따라 렌더링 할 수 있다.
(isSpecial이 true면? *를 굵게 출력하고, 아니라면 null)

useState

:컴포넌트에서 보여줘야 하는 내용이 사용자의 반응(클릭, 입력 등)에 따라 달라져야 할 때 활용한다.
useState는 리액트의 Hook중 하나이다.
useState를 사용 할 때에는 상태의 기본값을 파라미터로 넣어서 호출해준다.
이 함수를 호출해주면 배열이 반환된다.
Counter.js

import React from 'react';

function Counter() {
  const onIncrease = () => {
    console.log('+1')
  }
  const onDecrease = () => {
    console.log('-1');
  }
  return (
    <div>
      <h1>0</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

App.js

import React from 'react';
import Counter from './Counter';

function App() {
  return (
    <Counter />
  );
}

export default App;

이렇게 useState를 사용하지 않고, 함수만 선언했을 때는 console만 찍히게 된다.

이벤트를 만들어보자! ▼
Counter.js

import React, { useState } from 'react';

function Counter() {
  const [number, setNumber] = useState(0);

  const onIncrease = () => {
    setNumber(number + 1);
  }

  const onDecrease = () => {
    setNumber(number - 1);
  }

  return (
    <div>
      <h1>{number}</h1>
      <button onClick={onIncrease}>+1</button>
      <button onClick={onDecrease}>-1</button>
    </div>
  );
}

export default Counter;

const로 선언하여 useState를 만든다.
첫번째 원소는 현재 상태, 두번째 원소는 setter함수이다.
setter함수는 파라미터로 전달 받은 값을 최신 상태로 설정해준다.
useState안에는 기본, 초기값을 넣어준다.
이 코드의 경우 number:현재상태, setNumber:setter함수, 0:초기값이다.
onIncrease함수가 실행될 때, setNumber함수가 실행되며
전달받은 값을 최신 상태로 설정해준다.

input 상태 관리하기

:input태그는 사용자가 값을 입력할 수 있는 공간이다.
사용자가 입력한 값을 받아와 화면을 변화시켜야 한다.
input은 onChange라는 이벤트를 사용한다.
이벤트 객체 e를 파라미터로 받아와서 사용할 수 있는데, e.target.value를 조회하면 현재 input에 입력한 값이 출력된다.
InputSample.js

import React, { useState } from 'react';

function InputSample() {
  const [text, setText] = useState('');

  const onChange = (e) => {
    setText(e.target.value);
  };

  const onReset = () => {
    setText('');
  };

  return (
    <div>
      <input onChange={onChange} value={text}  />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: {text}</b>
      </div>
    </div>
  );
}

export default InputSample;

input에 onChange값을 넣어주고, onChange라는 함수를 할당한다.
onChange함수는 e를 파라미터로 받고, setText함수에 e.target.value를 넣어 input으로 받은 값을 최신값으로 나타내도록 한다.

여러개의 input관리

:input의 개수가 여러개가 됐을 때는, useState를 여러번 사용하고, onChange도 여러개 만들어서 사용해야 한다.
하지만 더 좋은 방법으로는,
input에 name을 설정하고, 이벤트가 발생했을 때 이 값을 참조하는 것이다.
InputSample.js

import React, { useState } from 'react';

function InputSample() {
   const [inputs, setInputs] = useState({
    name: '',
    nickname: ''
  });

  const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출

  const onChange = (e) => {
    const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
    setInputs({
      ...inputs, // 기존의 input 객체를 복사한 뒤
      [name]: value // name 키를 가진 값을 value 로 설정
    });
  };

  const onReset = () => {
    setInputs({
      name: '',
      nickname: '',
    })
  };


  return (
    <div>
      <input name="name" placeholder="이름" onChange={onChange} value={name} />
      <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;

useState에서는 문자열이 아니라 객체 형태로 관리해야 한다.
리액트에서 객체를 수정해야 할 때에는,
단순 얕은 복사로 수정할 수 없다.
따라서 새로운 객체를 만들고, 스프레드 ...문법을 사용하여 불변성을 지켜주어야 한다.
이 코드는,
1.input에서 사용자가 입력한 값을 받아 나타내기 위해 useState를 만들고,
이때 받아오는 방법은 같으나 받아올 값이 다른 '이름'과 '닉네임'이 있다.
2.useState를 만들어 안에 객체를 넣는다. 객체 안에는 '이름'과 '닉네임'정보를 담는다. 이때 이 객체는 여러개가 될 수 있다.
3.구조분해할당을 통해 값을 추출한다. useState의 기본값 '이름'과 '닉네임'이 inputs이 되어 현재 값이 되는 것
4.onChange함수를 만들고 이벤트를 파라미터로 넣는다.
우선 e.target에서 name과 value를 추출한다.
setInput setter함수를 호출하고 안에 변하는 최신값을 객체로 넣어준다.
...문법을 사용하여 얕은 복사를 하고, [name]:value로 name키를 가진 값을 value로 설정한다. 이렇게 복사한 값을 최신값으로 설정한다.
5.input안에 값을 넣어주는데, 둘 다 onChange 이벤트에 onChange함수를 넣어주고, value 값을 각각 '이름'과 '닉네임'으로 잡아준다.

profile
Developer ʕ ·ᴥ·ʔ ʕ·ᴥ· ʔ

0개의 댓글