본문 바로가기

WINK-(Web & App)/React.js 스터디

[2025 1학기 React.js 스터디] 이승준 #3주차

반응형

React.js가 탄생하게된 이유

리액트가 탄생하게 된 이유에 대해서 작성해보겠습니다...

<h2 id="number">0</h2>
<div>
  <button id="increase">+1</button>
  <button id="decrease">-1</button>
</div>
const number = document.getElementById('number');
const increase = document.getElementById('increase');
const decrease = document.getElementById('decrease');

increase.onclick = () => {
  const current = parseInt(number.innerText, 10);
  number.innerText = current + 1;
};

decrease.onclick = () => {
  const current = parseInt(number.innerText, 10);
  number.innerText = current - 1;
};

이런식으로 저번주에서 했던 것처럼 HTML에 UI를 제어하려면  DOM을 수정해주는 방식으로 제어해주었는데요, 이러한 방식은 코드가 복잡해지게 된다면 아래의 그림처럼 상당히 복잡해지게 됩니다. 이러면 유지보수 및 업데이트가 어렵게 되죠.

-->그래서 Ember, Backbone, AngularJS같은 프레임워크가 만들어졌는데요, 얘네들은 JS의 특정 값이 바뀌게 되면 DOM의 속성이 바뀌는 방식으로 웹개발의 어려움을 줄여줬습니다! BUT.. 리액트는 다름! --> 아예 처음부터 만들어버림 --> 속도가 느려질 수 있지만 virtual DOM이라는 걸 써서 해결했습니다.

 

- Virtual DOM이란?? --> 실제 존재하는게 아니라 메모리에서 존재하는 가상의 DOM입니다.(JS 객체)

- 장점 : JS객체이므로 속도가 빠름.

  1. 상태가 업데이트
  2. UI를 Virtual Dom이용해서 렌더링.
  3. 리액트 알고리즘으로 실제 보이는 DOM과 비교후 차이가 있는 곳을 감지
  4. 패치

리액트 컴포넌트

import React from 'react';

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

export default Hello;

이렇게 Hello.js를 만들어 주었습니다. 

리액트 컴포넌트를 만드려면 import React from 'react'로 리액트를 불러와야합니당. 여기서 컴포넌트가 뭔지 궁금증이 들어서 찾아봤습니다.

- 컴포넌트 --> 화면을 구성하는 조각입니다. (레고 블럭이라고 생각하면 편함) ex) 댓글 컴포넌트, 좋아요 컴포넌트 같은거 블럭..

export default Hello는 Hello라는 컴포넌트를 내보내겠다는겁니다. 다른 컴포넌트에서 재사용 가능.

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

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

export default App;

이런식으로 App.js파일을 만져줬는데요, import Hello from './Hello';로 Hello 컴포넌트를 불러왔구요 <Hello />를 여러번 사용했는데, 이처럼 재사용이 용이합니다.

index.js파일을 열어보면

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

이렇게 되는데요, 여기서 ReactDOM.render 의 역할은 브라우저에 있는 실제 DOM 내부에 리액트 컴포넌트를 렌더링하겠다는 것을 의미합니다. 여기서는 id가 root인 DOM을 선택하고 있는데 이는 index.html파일 내부에 있으며 만약 리액트가 렌더링되면 렌더링된 결과물이 id가 root인 div태그 내부에 렌더링 되는 것입니다. index.js파일에서 root.render(<App />);으로 앱안에 컴포넌트를 꽂아넣는다고 생각하면 됩니다.

 

JSX - HTML같지만 실제로는 JS

리액트 컴포넌트 파일에서 XML 형태로 코드를 작성하면 babel 이 JSX 를 JavaScript 로 변환을 해줍니다.

근데 여기서 정확히 리액트 JS소스에서 정확히 어느부분이 JSX인지 궁금했는데 밑에 누가 질문을 남겼더라구요.

return(...); 에 괄호안에 부분이 JSX문법으로 만들어져야 하는거라고 하네요, 그리고 그 밖은 그냥 JS라고 합니다.

 

JSX의 기본 문법 

  • 태그를 사용하면 무조건 태그를 닫아줘야한다.
 <p>
          Edit <code>src/App.js</code> and save to reload.
</p>

이런느낌으로 무조건 닫아줘야합니다. (HTML에서 input이나 br태그처럼 안닫아줘도 되는 태그들이 있는데 리액트에선 금지!! 무조건 닫아줘야 함)

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

-self closing 태그 --> 태그와 태그사이에 내용이 들어가지 않을때 사용. 열리고 바로 닫히는 태그 (위 코드에서는 <Hello />처럼 바로 열리고 닫히는 태그가 바로 self closing 태그이다.

 

두개 이상의 태그

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

function App() {
  return (
    <div>
      <Hello />
      <div>안녕히계세요</div>
    </div>
  );
}

export default App;

이런식으로 <Hello />태그와 <div>안녕히계세요></div>처럼 태그가 두개이상이면 무조건 하나의 태그로 감싸줘야합니다.

하지만 <div>태그로 감싸기에 제한사항이 많을 경우, fragment를 사용하면 됩니다.

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

function App() {
  return (
    <>
      <Hello />
      <div>안녕히계세요</div>
    </>
  );
}

export default App;

그냥 이런식으로 <>, </>로 쓰면 됩니다. 아무것도 안넣으면 됨. 이러면 fragment가 만들어지는데 이거는 그냥 묶는 용도지 브라우저에서 별도의 엘리먼트로 나타나질 않아요.

 

JSX내부에서 JS변수 사용할때

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

function App() {
  const name = 'react';
  return (
    <>
      <Hello />
      <div>{name}</div>
    </>
  );
}

export default App;

JSX내부에서 JS변수를 사용하고싶으면 위 코드에서 {name}과 같이 작성한 것처럼, {}로 묶어줘야합니다.

 

style과 ClassName

function App() {
  const name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24, // 기본 단위 px
    padding: '1rem' // 다른 단위 사용 시 문자열로 설정
  }
  return (
    <>
      <Hello />
      <div style={style}>{name}</div>
    </>
  );
}

여기서처럼 style을 사용할때 인라인 스타일들은 객체 형태로 작성해야하고, background-color처럼 -로 표현되어있는 이름들은 모두 backgroundColor처럼 CamelCase로 작성해야합니다. 여기서 CamelCase란???

- CamelCase -->

  •  단어랑 단어를 붙여 쓸 때
  • 첫 단어는 소문자
  • 그다음 단어 첫 글자는 대문자

그리고 CSS class를 설정 할 때는 class대신 className으로 설정해야함

 

주석

{/* 이런 형태로 /*} 작성합니다.

<Hello 
        // 열리는 태그 내부에서는 이렇게 주석을 작성 할 수 있습니다.
      />

또한, 이런식으로 열리는 태그 내부에서는 //로도 주석작성이 가능합니다.

 

Props 

부모 컴포넌트가 자식 컴포넌트한테 값 전달할 때 쓰는 것입니다.

예를 들어서, App 컴포넌트에서 Hello 컴포넌트를 사용 할 때 name 이라는 값을 전달해주고 싶다고 가정해봅시다. 그러면, 이렇게 코드를 작성하면 됩니다.

 

App.js

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

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

export default App;

 

이제, Hello 컴포넌트에서 name 값을 사용 하고 싶을 땐 어떻게 하면 되는지 알아볼까요?

 

Hello.js

import React from 'react';

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

export default Hello;

컴포넌트에게 전달되는 props 는 파라미터를 통하여 조회 할 수 있습니다. props 는 객체 형태로 전달되며, 만약 name 값을 조회하고 싶다면 props.name 을 조회하면 됩니다. --> 이게 뭔말이냐면 부모 컴포넌트 위에 App.js에 있는거 에서 Hello.js에 name이라는 props를 넘겨준건데, Hello.js에서 props라는 파라미터를 통해서 조회가능한건데, props.같은 형식으로 조회하면 된다. 

쉽게 설명해서 컴포넌트는 택배박스고, props는 물건임. 부모가 자식한테 택배에 props를 담아서 전달하는거라고 생각하면 된다.

 

<Hello name="react" color="red"/>

그리고 이런식으로 여러개도 가능하다.

import React from 'react';

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

export default Hello;

props 내부의 값을 조회 할 때마다 props. 를 입력하고 있는데, 함수의 파라미터에서 비구조화 할당(aka 구조 분해) 문법을 사용하면 조금 더 코드를 간결하게 작성 할 수 있습니다.

import React from 'react';

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

export default Hello;

원래 function Hello(props)였던 거에서 props대신에 {}으로 묶은 props들을 넣고, return 에서 props를 붙히지말고, 그냥 쓰면 된다.

근데 여기서 왜 props.만 안붙히는건데 color:까지 없어졌는지 궁금했다...... --> JS에서는 key와 value가 같으면 생략 가능하단다... 처음 안 사실 ㅎ

 

defaultProps

import React from 'react';

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

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

export default Hello;

만약 컴포넌트에 props를 지정하지 않았을 때 기본적으로 사용할 값을 지정하고싶다면 defaultProps를 사용해서 위 코드처럼 쓰면 된다고 해서 해봤는데... 이게 안됩니다..? 그래서 검색을 좀 해봤는데, React V-18.00부터는 지원하지 않는다고 하네요... 그래서 어떻게 하면 되냐면..

import React from 'react';

function Hello({ color, name = '이름없음' }) {
  return <div style={{ color }}>안녕하세요 {name}</div>
}

export default Hello;

이런식으로 그냥 props 값들 안에 이름 = '기본값'이런식으로 입력하면 된다고 합니다. --> 해봤더니 되네요..

 

props.children

컴포넌트 태그 사이에 넣은 값을 조회하고 싶을 땐, props.children 을 조회하면 된다.

 

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.js에서 props.children을 렌더링을 안해줘서 그런데요, 

import React from 'react';

function Wrapper({ children }) {
  const style = {
    border: '2px solid black',
    padding: '16px',
  };
  return (
    <div style={style}>
      {children}
    </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" isSpecial={true}/>
      <Hello color="pink" />
    </Wrapper>
  )
}

export default App;

그리고, Hello 컴포넌트에서는 isSpecial 이 true 이냐 false 이냐에 따라서 컴포넌트의 좌측에 * 표시를 보여줘보겠습니다.

이를 실행하기위해서 가장 기본적인 방법으로는 삼항 연산자를 사용합니다.

 

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;

bool ? 내용1 : 내용2 true면 내용1 false면 내용2. 그리고 JSX에서 null, false, undefined를 렌더링하면 나타나지 않는다네요.

그리고 이걸 좀더 단순화할 수 있는데요.

{isSpecial && <b>*</b>}

이런식으로 표현가능합니다. 앞에 값이 true면 뒤에 내용을 실행하고 false면 앞에 isSpecial(false)가 나타납니다. 이는 단축 평가 논리 계산법이라는 것을 따르는데, 이게 뭘까요>?

*단축 평가 논리 계산법
console.log(true && 'hello'); // hello - true이므로 hello출력
console.log(false && 'hello'); // false - false이므로 false

console.log('hello' && 'bye'); // bye - 'hello'라는 값이 존재하므로 bye출력
console.log(null && 'hello'); // null - null이므로 null
console.log(undefined && 'hello'); // undefined -undefined이므로 undefined
console.log('' && 'hello'); // '' - ''은 비어있는것이므로 ''
console.log(0 && 'hello'); // 0- 0은 false를 의미 그래서 0
console.log(1 && 'hello'); // hello - 1은 true를 의미 그래서 hello출력

이런거입니다. 그리고

<Hello name="react" color="red" isSpecial />

이런식으로 Props의 값을 정해주지 않으면, 기본적으로 {true}값이 들어갑니다.

 

✅ useState

함수형 컴포넌트에서 상태를 관리해주는 Hooks의 한 종류입니다. 동적인 값을 끼얹어주는 역할을 해줌.

이런식으로 새로 만들어 줬습니다.

 

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;

 

여기서 첫줄은 리액트 패키지에서 useState라는 함수를 호출해옵니다. 그리고

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

여기서는 useState 를 사용 할 때에는 상태의 기본값을 인자로 넣어서 호출해줍니다. 이 함수를 호출해주면 배열이 반환되는데요, 여기서 첫번째 원소는 현재 상태, 두번째 원소는 Setter 함수입니다.  근데 이걸 보면 뭔가 어색합니다. 뭔가 원래는...

const numberState = useState(0);
const number = numberState[0];
const setNumber = numberState[1];

이렇게 되어야 하는게 아닌가.. 하는 의구심이 들수있는데, 이는 비구조화 할당 방식을 사용해서 그렇습니다. 어? 이거 props할때 나왔는데? 맞습니다. 배열에도 비구조화 할당방식이 존재합니다. 

비구조화 할당방식이란?

“객체”나 “배열” 안에 있는 값들을 쉽게 꺼내서 변수에 담는 문법을 의미합니다.

객체 

const name = user.name;
const age = user.age;
const hobby = user.hobby;

const { name, age, hobby } = user;

console.log(name);  // Jake
console.log(age);   // 25
console.log(hobby); // LoL

이런식으로 원래 위 세줄처럼 할것을 중간처럼해서 변수를 꺼내주고, 맨아래 세줄처럼 사용하면 된다. user.을 굳이 붙힐 필요 X

 

배열

const arr = [10, 20, 30];

const a = arr[0];
const b = arr[1];
const c = arr[2];

const [a, b, c] = arr;

console.log(a);  // 10
console.log(b);  // 20
console.log(c);  // 30

맨위는 예시이고, 중간 세줄은 원래, 중간 한줄은 비구조화 할당방식을 사용해서 변수 할당. 마지막 세줄은 이렇게 그냥 사용하면 된다.

 

다시 돌아와서 Setter 함수는 파라미터로 전달받은 값을 최신 상태로 유지해줍니다.

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

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

 

함수형 업데이트

import React, { useState } from 'react';

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

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

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

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

export default Counter;

이 코드를 보면 아까 코드와는 다르게 다음 값을 업데이트해주는게 아니라 기존값에 기존값+1값을 넣어서 수정하는 형태로 짜줬다. 이를 함수형 업데이트라고 한다. 함수형 업데이트는 주로 나중에 컴포넌트를 최적화를 하게 될 때 사용하게 됩니다.

 

Input 태그 상태 관리하기

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;

이번에도 useState 를 사용합니다. 이번에는 input 의 onChange 라는 이벤트를 사용하는데요, 이벤트에 등록하는 함수에서는 이벤트 객체 e 를 파라미터로 받아와서 사용 할 수 있는데 이 객체의 e.target 은 이벤트가 발생한 DOM 인 input DOM 을 가르키게됩니다. 이 DOM 의 value 값, 즉 e.target.value 를 조회하면 현재 input 에 입력한 값이 무엇인지 알 수 있습니다. 이 값을 useState 를 통해서 관리를 해주면 됩니다.

 

그런데 여기서 이벤트 객체가 무엇일까요? 이벤트 객체란 쉽게 말하면 이벤트가 발생했을때 발생하는 모든 정보들을 다 들고있는 객체라고 생각하시면 됩니다.

 

input 의 상태를 관리할 때에는 input 태그의 value 값도 설정해주는 것이 중요합니다. 그렇게 해줘야, 상태가 바뀌었을때 input 의 내용도 바뀝니다.

 

✅ 여러개의 Input 태그 관리하기

input의 개수가 여러개가 되었다고해서 useState와 onChange를 여러개를 써서 하는것은 가능은 하지만 좋은 방법은 아닙니다.

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;
  • inputs는 입력하는 값을 받는 객체, setInputs는 상태 업데이트함수, name, nickname을 초깃값을 ''로 해줌.
  • name, nickname을 비구조화 할당을 통해서 값 추출해줌.
  • e.target에서 name과 value를 추출.
  • inputs[name] = value;처럼 직접 객체를 수정하면 안됩니다. 그대신 setInputs({...inputs,[name] : value});처럼 새로운 객체를 만들어서 수정을 해야합니다. 여기서 spread 문법을 사용했는데요...

spread 문법

 

객체의 내용을 모두 "펼쳐서" 기존 객체를 복사해주는데요, 이러한 작업을, "불변성을 지킨다" 라고 부릅니다. 불변성을 지켜주어야만 리액트 컴포넌트에서 상태가 업데이트가 됐음을 감지하고, 이에 따라 필요한 리렌더링이 진행됩니다. 만약에 직접 inputs[name] = value 이런식으로 기존 상태를 직접 수정하게 되면, 값을 바꿔도 리렌더링이 되지 않습니다.

이것에 대해서 더 자세히 알아보겠습니다. 이해가 잘 안돼서 폭풍 검색을 했는데요, 리액트는 기본적으로 prevState와 newState가 다르면 감지해서 리렌더링을 진행하는데, 기존 객체를 그냥 직접 수정해버리면 prevState === newState가 되어버려서 리액트는 내가 수정을 한건지 만건지 감지가 안됩니다. 그래서 리렌더링이 진행되지 않는것이죠...

추가적으로, 리액트에서는 불변성을 지켜주어야만 컴포넌트 업데이트 성능 최적화를 제대로 할 수 있습니다.

 

✅ 과제

Introduce.js

import React, {useState} from 'react';

function Introduce({name, age, hobby}){
    const favoriteFood =['햄버거', '라면', '족발', '김치찌개', '홍어', '회', '간장게장'];
    const [food, setFood] = useState(0);
    
    const foodChange = () => {
        setFood(cfood => (cfood + 1) % favoriteFood.length);
    }

    return (
        <div>
            <h4>이름 : {name}</h4>
            <h4>나이 : {age}</h4>
            <h4>취미 : {hobby}</h4>
            <h4>좋아하는 음식 : {favoriteFood[food]}</h4>
            <button onClick = {foodChange}>음식 바꾸기</button>
        </div>
    )
}
export default Introduce;

이렇게 새로 Introduce.js를 만들어줬는데 일단 name, age, hobby를 props로 받아오고 음식들을 넣어준 배열을 만들었습니다. 그리고 useState(0)으로 인덱스에 쓰일 값을 0으로 초기화 시켜주었구요, foodChange 화살표 함수를 이용해서 인덱스 범위가 넘어가게 되면 다시 나머지 연산을 해줘서 다시 돌아오게끔 해줬습니다. 그리고 리턴값에 이름, 나이, 취미, 좋아하는 음식을 넣어주었구요, favoriteFood[]인덱스 안에 입력되는 값인 food를 받아와서 인덱스로 넣어주었습니다. 그러고 버튼을 하나 만들어 주었구요, 버튼이 클릭되면 foodChange함수가 실행되게 해서 배열을 돌리게끔 해주었습니다. 그리고 name, age, 등등에 모두 {}를 붙혀준것을 볼 수 있는데요, 이는 앞에서 얘기했다시피 jsx안에서 js관련 변수가 들어갈때는 {}를 씌워주어야해서 그렇습니다.

 

App.js

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

function App() {
  const containerStyle = {
    border : '1px solid black',
    padding : '20px',
    width : '160px',
    height : '190px',
    display : 'flex',
    justifyContent : 'center',
    alignItems : 'center'
    
  }

  const style = {
    display : 'flex',
    justifyContent : 'center',
    alignItems : 'center',
    height : '100vh',
    flexDirection : 'column'
    
  }
  return (
    <div style={style}>
      <h1>자기소개 카드</h1>
      <div style={containerStyle}>
        <Introduce name='이승준' age='23' hobby='게임' />
      </div>
    </div>
  );
}

export default App;

일단 이런식으로 완성했었는데, 웹클컴에서 들었던 실력을 조금 발휘해서 css를 짜주었구요, 초깃값을 안찍어줬기에 name, age, hobby를 써줬습니다. 근데 이렇게 했더니...

이런식으로 라면같이 짧은 글자는 가운데정렬인데..
김치찌개같이 긴것은 왼쪽으로 밀리네요..

네 이러한 문제가 있었습니다! 사소한 문제지만... 이는 containerStyle에서 justifyContent : 'center'을 삭제해줌으로써 해결해주었습니다. 그후는 정상적으로 작동했습니다!

 

 

 

 

휴 생각보다 오래걸렸군요... 그럼 20000

반응형