'css'는 'styled-components' 라이브러리에서 제공하는 함수로, CSS를 작성할 수 있는 방식 중 하나이다.

'css' 함수를 사용하면 CSS코드를 작성하고, 이를 자바스크립트 변수로 저장하고 재사용 가능하다.

 

아래코드에서 'const buttonStyles = css'는 'styled-components'css 함수를 사용하여 CSS 속성을 정의한 것이다. 이렇게 정의된 CSS 속성은 다른 'styled-components' 스타일 컴포넌트에서도 재사용할 수 있다. 이는 코드의 재사용성을 높여서 작성해야할 CSS 코드의 양을 줄이고, 유지보수성을 높일 수 있다.

 

1. ButtonStyles.js

import { css } from "styled-components";

const buttonStyles = css`
  cursor: pointer;
  border-radius: 8px;
  height: 50px;
  width: 200px;
  font-weight: 600;
  background-color: rgb(255, 255, 255);
`;
 
export default buttonStyles;

 

${props => ...}는 styled-components에서 props를 받아서 해당 CSS 속성을 동적으로 변경할 수 있는 기능이다. 이를 "styled-components의 props" 또는 "interpolated function" 이라고도 한다.

 

여기서 props는 해당 컴포넌트가 렌더링될 때 전달되는 속성값(property)들을 객체 형태로 가지고 있는 변수이다. 예를 들어, small 속성값이 해당 컴포넌트에 전달되면, props.small은 true가 된다.

따라서, 위 코드에서 ${props => props.small && css는 props 객체 안에 small 속성값이 전달되면 그 값이 true이면, css 함수를 실행하라는 의미이다. && 연산자("and")는 좌항이 true일 때만 우항을 실행하기 때문에, props.small이 true일 때만 해당 CSS 속성을 적용하게 된다! 

정리하면 'props.small && css'는 'props' 객체의 small 속성이 truthy한 경우에만 css를 반환하도록 하는 것이다.

 

위랑 같은말

props.small은 Button 컴포넌트에서 small prop이 전달되었는지 여부를 나타내며, css 함수는 해당 CSS 속성을 동적으로 생성하기 위한 함수이다. 이 경우 props.small이 true인 경우에만 해당 CSS 속성이 생성되어 적용된다.

즉, 위 코드에서 ${props => props.small && css ... }는 small prop이 전달되면 해당 CSS 속성('small' 스타일)을 동적으로 생성하고, 그렇지 않으면 해당 CSS 속성을 생성하지 않는다(일반적인 스타일).

 

2. Button.jsx

import React from 'react'
import styled from 'styled-components'
import buttonStyles from '../styles/ButtonStyles'
import { css } from 'styled-components'

const Button = () => {
    return (
        <>
        <PrimaryButton>Large Primary Button</PrimaryButton>
        <PrimaryButton medium>Medium</PrimaryButton>
        <PrimaryButton small>Small</PrimaryButton>
        </>
  )
}

export default Button;

const PrimaryButton = styled.button`
    ${buttonStyles}
    border: 3px solid rgb(85, 239, 196);
    color: rgb(0, 0, 0);

    ${props =>
        props.medium && css`
        border: none;
        background-color: rgb(85, 239, 196);
        height: 45px;
        width: 130px; 
        `}

    ${props =>
        props.small && css`
        border: none;
        background-color: rgb(85, 239, 196);
        height: 40px;
        width: 100px; 
    `}    
`

1. UUID란?

네트워크 상에서 서로 모르는 개체들을 식별하고 구별하기 위해서는 각각의 고유한 이름이 필요하다. 이 이름은 고유성(유일성)이 매우 중요하다. 같은 이름을 갖는 개체가 존재한다면 구별이 불가능해 지기 때문이다. 이를 위하여 탄생한 것이 범용고유식별자(UUID)이며 국제기구에서 표준으로 정하고 있다.

UUID 표준에 따라 이름을 부여하면 고유성을 완벽하게 보장할 수는 없지만 실제 사용상에서 중복될 가능성이 거의 없다고 인정되기 때문에 많이 사용되고 있다.

16 옥텟 (128비트)의 수이다. 표준 형식에서 UUID는 32개의 십육진수로 표현되며 총 36개 문자(32개 문자와 4개의 하이픈)로 된 8-4-4-4-12라는 5개의 그룹을 하이픈으로 구분한다.

예를 들면

ID : 86d705d6-67f4-45ab-a9a0-4da3a0241911

 

2. 알게 된 계기

과제 만들던 중 제한사항을 보고 구글링 하다 랜덤으로 고유번호를 부여한다는 것을 보고 찾아보게 되었다.

* 제한사항* Todo Id 생성 시 todos.length 사용해서 생성하지 않습니다. todos.length 을 사용해서 id 생성 시 발생할 수 있는 문제점에 대해 고민해보시길 바랍니다.

 

3. 사용방법

터미널에 설치하고,

 

필요한 컴포넌트에 import하고,

import { v4 as uuidv4 } from "uuid";

쓰면됨!

const uniqueId = () => {
    return uuidv4()
  }

 

4. 굳이 UUID를 사용해서 만들어야 할까?

답을 찾는 중..

 

 

 

 

 

개요출처

https://ko.wikipedia.org/wiki/%EB%B2%94%EC%9A%A9_%EA%B3%A0%EC%9C%A0_%EC%8B%9D%EB%B3%84%EC%9E%90

렌더링

컴포넌트가 현재 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업을 의미한다.

리렌더

React가 데이터의 변화에 따라서 화면을 다시 그리는 현상이다.


리-렌더링의 발생 조건

  1. 컴포넌트에서 state가 바뀌었을 때
  2. 컴포넌트가 내려받은 props가 변경되었을 때
  3. 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두

https://mynzero.tistory.com/28

state

state가 변했으면 리렌더링 하는 것이고, state가 변하지 않았으면 리렌더링을 하지 않는다

state가 변했는지 변하지 않았는지 확인하는 방법이 state의 변화 전, 후의 메모리 주소를 비교한다.

그래서 만약 리액트에서 원시데이터가 아닌 데이터를 수정할 때 불변성을 지켜주지 않고, 직접 수정을 가하면 값은 바뀌지만 메모리주소는 변함이 없게 된다. 그래서 즉, 개발자가 값은 바꿨지만 리액트는 state가 변했다고 인지하지 못하게 되고, 결국 마땅히 일어나야 할 리렌더링이 일어나지 않게되는 것이다.

State 불변성https://mynzero.tistory.com/18

props

props란 결국 부모 컴포넌트가 자식에게 넘겨준 데이터들의 묶음이라고 볼 수 있으며,

리액트에서는 Props를 통해 부모 컴포넌트로부터 자식 컴포넌트에 데이터를 넘겨줄 수 있다.

일반적인 렌더링

리액트의 기본적인 동작은 부모 컴포넌트가 렌더링되면, 리액트는 모든 자식 컴포넌트를 순차적으로 리렌더링 한다는 것이다.

(1) 리-렌더링의 발생 조건

  1. 컴포넌트에서 state가 바뀌었을 때
  2. 컴포넌트가 내려받은 props가 변경되었을 때
  3. 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두

(2) 최적화

리액트에서 리렌더링이 빈번하게, 자주 일어난다는 것은 그렇게 좋은 소식은 아니ek. 비용이 발생하는 것은 최대한 줄여야 한다. 이런 작업을 우리는 최적화(Optimization).

리액트에서 불필요한 렌더링이 발생하지 않도록 최적화하는 대표적인 방법은

  • memo(React.memo) : 컴포넌트를 캐싱
  • useCallback : 함수를 캐싱
  • useMemo : 값을 캐싱

memo(React.memo)

: 리-렌더링의 발생 조건 중 3번째 경우. 즉, 부모 컴포넌트가 리렌더링 되면 자식컴포넌트는 모두 리렌더링 된다.

부분을 돕는 도구가 바로 React.memo!!

컴포넌트를 메모리에 저장해두고 필요할 때 갖다 쓰게 됩니다. 이렇게 하면 부모 컴포넌트의 state의 변경으로 인해 props가 변경이 일어나지 않는 한 컴포넌트는 리렌더링 되지 않아요. 이것을 컴포넌트 memoization 이라고 한다.

export default React.memo(Box1);
export default React.memo(Box2);
export default React.memo(Box3);

useCallback

: 인자로 들어오는 함수 자체를 기억(메모이제이션)

?? : React.memo를 통해서 Box1.jsx는 메모이제이션을 했는데도 리렌더링이 되네요?

네, 그것은 우리가 함수형 컴포넌트를 사용하기 때문이고 App.jsx가 리렌더링 되면서 코드가 다시 만들어지기 때문이다.

자바스크립트에서는 함수도 객체의 한 종류에요. 따라서 모양은 같더라도 다시 만들어지면 그 주솟값이 달라지고 이에 따라 하위 컴포넌트인 Box1.jsx는 props가 변경됐다고 인식한다.

const onInitButtonClickHandler = () => {
  initCount();
};

이 함수를 메모리 공간에 저장해놓고, 특정 조건이 아닌 경우엔 변경되지 않도록 하려면?

// 변경 후
const initCount = useCallback(() => {
  setCount(0);
}, []);

count를 초기화 할 때, 콘솔을 찍으려멱?

...

// count를 초기화해주는 함수
const initCount = useCallback(() => {
  console.log(`[COUNT 변경] ${count}에서 0으로 변경되었습니다.`);
  setCount(0);
}, []);

...

: [COUNT 변경] 0에서 0으로 변경되었습니다.

이런 현상이 발생하는 이유는, useCallback이 count가 0일 때의 시점을 기준으로 메모리에 함수를 저장했기 때문이다. 이 때문에 우리는 dependency array가 필요하다.

기존 코드의 dependency array에 count를 넣으면, count가 변경 될 때 마다 새롭게 함수를 할당한다.

...

// count를 초기화해주는 함수
const initCount = useCallback(() => {
  console.log(`[COUNT 변경] ${count}에서 0으로 변경되었습니다.`);
  setCount(0);
}, [count]);

...

useMemo

: 여기서 말하는 memo는 memoization을 뜻한다. 기억한다는 말이다.

동일한 값을 반환하는 함수를 계속 호출해야 하면 필요없는 렌더링을 한다고 볼 수 있다. 맨 처음 해당 값을 반환할 때 그 값을 특별한 곳(메모리)에 저장한다.. 이렇게 하면 필요할 때 마다 다시 함수를 호출해서 계산하는게 아니라 이미 저장한 값을 단순히 꺼내와서 쓸 수 있다. 보통 이러한 기법을 캐싱을 한다. 라고 표현한다.

 

사용방법

dependency Array의 값이 변경 될 때만 **반환할_함수()**가 호출된다.

그 외의 경우에는 memoization 해놨던 값을 가져오기만 한다.

// as-is
const value = 반환할_함수();

// to-be
const value = useMemo(()=> {
	return 반환할_함수()
}, [dependencyArray]);
const me = useMemo(() => {
  return {
    name: "Ted Chang",
    age: 21,
    isAlive: isAlive ? "생존" : "사망",
  };
}, [isAlive]);

~~

~~ 나중에 적기

useMemo()만 이렇게 써주면, uselessCount가 아무리 증가돼도 영향이 없게 된다.

 

주의해야 할 사항

useMemo를 남발하게 되면 별도의 메모리 확보를 너무나 많이 하게 되기 때문에 오히려 성능이 악화될 수 있다.

필요할 때만 쓰기😎

'React' 카테고리의 다른 글

axios interceptor  (0) 2023.04.29
비동기 통신 - axios(get)  (0) 2023.04.28
React Hooks - useRef  (0) 2023.04.19
React Hooks - useEffect  (0) 2023.04.19
React Component  (0) 2023.04.18

useRef

DOM 요소에 접근할 수 있도록 하는 React Hook!

✔예를 들면 화면이 렌더링 되자마자 특정 input 태그가 focusing이 돼야 하는 경우 등

 

사용방법

그리고, 변경도 가능해요!

import "./App.css";
import { useRef } from "react";

function App() {
  const ref = useRef("초기값");
  console.log("ref", ref);
  
//  function App() {
//  const ref = useRef("초기값");
//  console.log("ref 1", ref);

//  ref.current = "바꾼 값";
//  console.log("ref 1", ref);

  return (
    <div>
      <p>useRef에 대한 이야기에요.</p>
    </div>
  );
}

export default App;

 

⭐이렇게 설정된 ref 값은 컴포넌트가 계속해서 렌더링 되어도 unmount 전까지 값을 유지한다!

이러한 특징 때문에 useRef는 다음 2가지 용도로 사용된다.

1. 저장공간

- state와 비슷한 역할을 해요. 다만 state는 변화가 일어나면 다시 렌더링이 일어나요. 내부 변수들은 초기화가 되죠.

- ref에 저장한 값은 렌더링을 일으키지 않아요. 즉, ref의 값 변화가 일어나도 렌더링으로 인해 내부 변수들이 초기화 되는 것을 막을 수 있죠.

- 컴포넌트가 100번 렌더링 → ref에 저장한 값은 유지돼요.

정리하면

state는 리렌더링이 꼭 필요한 값을 다룰 때 쓰면 된다.

ref는 리렌더링을 발생시키지 않는 값을 저장할 때 사용한다.

2. DOM

- 렌더링 되자마자 특정 input이 focusing 돼야 한다면 useRef를 사용하면 된다.

 

state와 ref의 차이점

state는 변경되면 렌더링이 되고, ref는 변경되면 렌더링이 안된다는걸 다시 한번 기억하기!!!

 

DOM 접근

<input /> 태그에는 ref라는 속성이 있다. 이걸 통해 우리는 해당 DOM 요소로 접근할 수 있다.

useRef 사용하여 포커싱 주기

import { useEffect, useRef } from "react";
import "./App.css";

function App() {
  const idRef = useRef("");

  // 렌더링이 될 때
  useEffect(() => {
    idRef.current.focus();
  }, []);

  return (
    <>
      <div>
        아이디 : <input type="text" ref={idRef} />
      </div>
      <div>
        비밀번호 : <input type="password" />
      </div>
    </>
  );
}

export default App;

아이디가 10자리 입력되면 자동으로 비밀번호 필드로 이동하는 코드

import { useEffect, useRef, useState } from "react";
import "./App.css";

function App() {
  const idRef = useRef("");
  const pwRef = useRef("");

  const [id, setId] = useState("");

  const onIdChangeHandler = (event) => {
    setId(event.target.value);
  };

  // 렌더링이 될 때
  useEffect(() => {
    idRef.current.focus();
  }, []);

  // 왜 useEffect 안에 놓았을까요?
  useEffect(() => {
    if (id.length >= 10) {
      pwRef.current.focus();
    }
  }, [id]);

  return (
    <>
      <div>
        아이디 :
        <input
          type="text"
          ref={idRef}
          value={id}
          onChange={onIdChangeHandler}
        />
      </div>
      <div>
        비밀번호 : <input type="password" ref={pwRef} />
      </div>
    </>
  );
}

export default App;

비밀번호 타입이 패스워드? -> 숫자 가려줌

 

id.length ≥ 10 이 로직을 useEffect 안에 넣었는지?

아이디가 하나하나 바뀔 때마다 화면이 계속해서 바뀐다 -> state가 갱신되고 있다. -> 랜더링이 다시 계속해서 된다.

state가 바뀔 때마다 어떤 것(id가 입력된 길이가 10자리냐 아니냐)을 파악해야 한다.

[id]값이 바뀔 때마다 수행이 돼야 하기 때문에.

'React' 카테고리의 다른 글

비동기 통신 - axios(get)  (0) 2023.04.28
React Hooks - 최적화(React.memo, useCallback, useMemo)  (1) 2023.04.19
React Hooks - useEffect  (0) 2023.04.19
React Component  (0) 2023.04.18
State 불변성  (0) 2023.04.15

useEffect

리액트 컴포넌트가 렌더링될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다. 쉽게 말해 어떤 컴포넌트가 화면에 보여졌을 때 내가 무언가를 실행하고 싶다면? 또는 어떤 컴포넌트가 화면에서 사라졌을 때 무언가를 실행하고 싶다면? useEffect를 사용한다.

React에서 제공하는 훅 (기능) 이므로, import React, { useEffect } from "react";import 해서 사용합니다.

 

useEffect는 화면에 컴포넌트가 mount 또는 unmount 됐을 때 실행하고자 하는 함수를 제어하게 해주는 훅이다.

useEffect 에서 함수를 1번만 실행시키고자 할때는 의존성 배열을 빈 배열로 둔다.

 

useEffect 기초

App 컴포넌트가 화면에 렌더링될 때 useEffect 안에 있는 console.log가 실행된다. 컴포넌트가 렌더링 될 때 실행되는 것, 이게 바로 useEffect 핵심 기능이다.

// src/App.js

import React, { useEffect } from "react";

const App = () => {

  useEffect(() => {
		// 이 부분이 실행된다.
    console.log("hello useEffect");
  });

  return <div>Home</div>;
}

export default App;

 

useEffect와 리렌더링(re-rendering)

useEffect는 useEffect가 속한 컴포넌트가 화면에 렌더링 될 때 실행된다. 이런 useEffect의 특징에 의해 우리가 의도치않은 동작을 경험할수도 있다.

console.log("hello useEffect"); 가 계속 실행되서 브라우저 콘솔에 텍스트가 계속 올라오는 것을 볼 수 있다.

import React, { useEffect, useState } from "react";

const App = () => {
  const [value, setValue] = useState("");

  useEffect(() => {
    console.log("hello useEffect");
  });

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
    </div>
  );
}

export default App;

전체 흐름은 아래와 같다.

  1. input에 값을 입력한다.
  2. value, 즉 state가 변경된다.
  3. state가 변경되었기 때문에, App 컴포넌트가 리렌더링 된다.
  4. 리렌더링이 되었기 때문에 useEffect가 다시 실행된다.
  5. 1번 → 5번 과정이 계속 순환환다.

의존성 배열

: 이 배열에 값을 넣으면 그 값이 바뀔 때만 useEffect를 실행하는 것!

// useEffect의 두번째 인자가 의존성 배열이 들어가는 곳 입니다.
useEffect(()=>{
	// 실행하고 싶은 함수
}, [의존성배열])

의존성 배열이 빈 배열인 경우 [ ]

아무것도 넣지 않았으니 useEffect는 처음에 딱 한번만 실행되고 그 이후로는 어떤일이 일어나도 실행이 되서는 안된다.

input에 어떤 값을 입력하더라도, 처음에 실행된 hello useEffect외에는 더 이상 실행이 되지 않는 것을 볼 수 있다. 이렇게 useEffect를 사용하는데, 어떤 함수를 컴포넌트가 렌더링 될 때 단 한번만 실행하고 싶으면 의존성 배열을 [ ] 빈 상태로 넣으면 된다.

 

의존성 배열에 값이 있는 경우 [의존성배열]

의존성 배열에 value 를 넣는다. 우리가 배운게 맞다면, value는 state이고 우리가 input을 입력할 때마다 그 값이 변하게 되니 useEffect도 계속 실행이 된다.

'React' 카테고리의 다른 글

React Hooks - 최적화(React.memo, useCallback, useMemo)  (1) 2023.04.19
React Hooks - useRef  (0) 2023.04.19
React Component  (0) 2023.04.18
State 불변성  (0) 2023.04.15
State  (0) 2023.04.15

useState

: 가장 기본적인 hook이며, 함수 컴포넌트에서 가변적인 상태를 가지게 해준다.

기본적인 형태는

const [state, setState] = useState(initialState);

래는 useState 라는 함수가 배열을 반환하고, 이것을 구조 분해 문법으로 꺼내놓은 모습일 뿐이다. 우리는 state를 변수로 사용했고, setState를 이용해서 state 값을 수정할 수 있었다. 그리고 만약 state가 원시 데이터타입이 아닌 객체 데이터 타입인 경우에는 불변성을 유지해줘야 한다고 이미 배웠다.

 

함수형 업데이트

: setState를 사용하는 방식에는 우리가 알고 있는 방식이 아닌 또 다른 방식이 있다. 함수형 업데이트 방식!

// 기존에 우리가 사용하던 방식
setState(number + 1);

// 함수형 업데이트 
setState(() => {});

위 코드와 같이 setState의 ( ) 안에 수정할 값이 아니라, 함수를 넣을 수 있다. 그리고 그 함수의 인자에서는 현재의 state을 가져올 수 있고, { } 안에서는 이 값을 변경하는 코드를 작성할 수 있다.

// 현재 number의 값을 가져와서 그 값에 +1을 더하여 반환한 것 입니다.
setState((currentNumber)=>{ return currentNumber + 1 });

두 방식의 차이점?

일반 업데이트 방식으로 onClick안에서 setNumber(number + 1) 를 3번 호출했다. number가 1씩 증가한다.

이번에는 함수형 업데이트 방식으로 동일하게 작동시켜보면, number가 3씩 증가한다.

// src/App.js

import { useState } from "react";

const App = () => {
  const [number, setNumber] = useState(0);
  return (
    <div>
			{/* 버튼을 누르면 3씩 플러스 된다. */}
      <div>{number}</div>
      <button
        onClick={() => {
          setNumber((previousState) => previousState + 1);
          setNumber((previousState) => previousState + 1);
          setNumber((previousState) => previousState + 1);
        }}
      >
        버튼
      </button>
    </div>
  );
}

export default App;

이유는?

일반 업데이트 방식은 버튼을 클릭했을 때 첫번째 줄 ~ 세번째 줄의 있는 setNumber가 각각 실행되는 것이 아니라, 배치(batch)로 처리한다. 즉 우리가 onClick을 했을 때 setNumber 라는 명령을 세번 내리지만, 리액트는 그 명령을 하나로 모아 최종적으로 한번만 실행을 시긴다. 그래서 setNumber을 3번 명령하던, 100번 명령하던 1번만 실행된다.

반면에 함수형 업데이트 방식3번을 동시에 명령을 내리면, 그 명령을 모아 순차적으로 각각 1번씩 실행시킨다. 0에 1더하고, 그 다음 1에 1을 더하고, 2에 1을 더해서 3이라는 결과가 우리 눈에 보이는 것이다.

컴포넌트를 통해 UI를 재사용이 가능한 개별적인 여러 조각으로 나누고, 각 조각을 개별적으로 살펴볼 수 있다. 개념적으로 컴포넌트는 JavaScript 함수와 유사하다. “props”라고 하는 임의의 입력을 받은 후, 화면에 어떻게 표시되는지를 기술하는 React 엘리먼트(element:요소)를 반환한다.

 

리액트 컴포넌트(블럭, 즉 함수(html을 return하는 함수))를 표현하는 두 가지 방법

1. 함수형 컴포넌트(많이 사용)

// props라는 입력을 받음
// 화면에 어떻게 표현되는지를 기술하는 React 엘리먼츠를 반환(return)

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 훨씬 쉬운 표현을 해보면 아래와 같죠.
function App () {
	return <div>hello</div>
}

2. 클래스형 컴포넌트

 

Component 보는 방법

// 컴포넌트 밖, 내가 필요한 파일을 가져오는 영역
import React from 'react'; 
function App() {
  
	// <---- 자바스크립트 영역 ---->
	const handleClick = () => {
    alert('클릭!');
  };
  
  return (
  /* <---- HTML/JSX 영역  ---->*/
	<div
      style={{
        height: '100vh',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      <span>이것은 내가 만든 App컴포넌트 입니다</span>
      <button onClick={handleClick}>클릭!</button>
    </div>
  );
}
   {/* 이곳에 퀴즈를 위한 html 코드를 작성해 주세요 */}
    </div>
  );
}
// 내가 만든 컴포넌트를 밖으로 내보내는 영역
export default App;

 

 

주의!

컴포넌트를 만들 때 반드시 가장 첫 글자는 대문자로 만들어야 한다.

폴더는 소문자로 시작하는 카멜케이스로 작성하고, 컴포넌트를 만드는 파일은 대문자로 시작하는 카멜케이스로 이름을 짓는다.

 

부모-자식 컴포넌트

컴포넌트 안에 컴포넌트 넣기

컴포넌트는 다른 컴포넌트를 품을 수 있다. 이때 다른 컴포넌트를 품는 컴포넌트를 부모 컴포넌트라고 부르고, 다른 컴포넌트 안에서 품어지는 컴포넌트를 자식 컴포넌트라고 부른다.

import React from "react";

function Child() {
  return <div>연결 성공</div>;
}

function Mother() {
  return <Child />;
}

function GrandFather() {
  return <Mother />;
}

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

export default App;

이렇게 코드를 작성하면 "연결 성공" 문장이 보여진다. 이 파일에서 내보내진( “내보내진” 이라는 것을 export default 라고 하기로 했다.) 컴포넌트는 App 컴포넌트 이기때문에 App 컴포넌트가 화면에 보여진다. 하지만 App 컴포넌트는 GrandFather 컴포넌트를 자식으로 삼고, GrandFather -> Mother, Mother  ->  Child

그래서 결국 자식 컴포넌트에 있는 “연결 성공" 라는 문장이 보여지게 되는 것 이다.

'React' 카테고리의 다른 글

React Hooks - useRef  (0) 2023.04.19
React Hooks - useEffect  (0) 2023.04.19
State 불변성  (0) 2023.04.15
State  (0) 2023.04.15
Props, Props Children, Props 추출  (0) 2023.04.14

: 메모리에 있는 값을 변경할 수 없는 것!

 

원시 데이터(숫자, 문자, 불리언... ) : 불변성 있음

원시데이터는 수정을 했을 때 메모리에 저장된 값 자체는 바꿀 수 없고, 새로운 메모리 저장공간에 새로운 값을 저장한다.

 

원시데이터가 아닌 것들(배열, 객체, 함수... ) : 불변성 없음

원시데이터가 아닌 데이터는 수정했을 때 기존에 저장되어 있던 메모리 저장공간의 값 자체를 바꿔버린다.

왜 리액트에서는 원시데이터가 아닌 데이터의 불변성을 지켜주는 것을 중요시할까?

: state가 변했으면 리렌더링 하는 것이고, state가 변하지 않았으면 리렌더링을 하지 않는다.

state가 변했는지 변하지 않았는지 확인하는 방법이 state의 변화 전, 후의 메모리 주소를 비교한다. 그래서 만약 리액트에서 원시데이터가 아닌 데이터를 수정할 때 불변성을 지켜주지 않고, 직접 수정을 가하면 값은 바뀌지만 메모리주소는 변함이 없게 된다.

즉, 개발자가 값은 바꿨지만 리액트는 state가 변했다고 인지하지 못하게 된다. 그래서 결국 마땅히 일어나야 할 리렌더링이 일어나지 않게된다.

 

리액트 불변성 지키기 예시

배열을 setState 할 때 불변성을 지켜주기 위해, 직접 수정을 가하지 않고 전개 연산자를 사용해서 기존의 값을 복사하고, 그 이후에 값을 수정하는 식으로 구현합니다.

import React, { useState } from "react";

function App() {
  const [dogs, setDogs] = useState(["진돗개"]);

  function onClickHandler() {
		// spread operator(전개 연산자)를 이용해서 dogs를 복사합니다. 
	  // 그리고 나서 항목을 추가합니다.
    setDogs([...dogs, "한국의 토종견"]);
  }

  console.log(dogs);
  return (
    <div>
      <button onClick={onClickHandler}>버튼</button>
    </div>
  );
}

export default App;

index.js에서 주석처리하면 아래처럼 콘솔에서 하나만 나옴

 

랜더링

: 컴포넌트가 현재 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업

 

배열 또는 객체가 나온다면 스프레드 문법 or map or filter,

불변성을 지켜주는 여러가지 방법이용해서 원시데이터가 아닌 것을 처리한다 

import React, { useState } from "react";

function App() {
  const [dogs, setDogs] = useState({
    name: 'merry',
    age: 5,
  });

  return (
    <div>
      <div>{dogs.name}</div>
      <button 
       onClick={() => {
        dogs.name = 'cutemerry'
        const dogs2 = { ...dogs }
        setDogs(dogs2)
      }}>
        버튼
        </button>
    </div>
  );
}

export default App;

'React' 카테고리의 다른 글

React Hooks - useEffect  (0) 2023.04.19
React Component  (0) 2023.04.18
State  (0) 2023.04.15
Props, Props Children, Props 추출  (0) 2023.04.14
JSX(JavaScript + XML)  (0) 2023.04.14

: 컴포넌트 내부에서 바뀔 수 있는 값! (리액트 안에서 변경되어야 하는 값은 반드시 state로 선언)

왜? UI를 바꾸기 위해서

 

State를 만들기

useState() : '훅' (리액트에만 존재하는 개념이자 기능)

import React, { useState } from 'react';

function PororoFriends() {
  const [name, setName] = useState("루피"); // 이것이 state!
  return <Second PororoFriends={name} />;
}

// .. 중략

useState 훅을 사용하는 방식

const [ value, setValue ] = useState( 초기값 ) => ( ' ' )가능   // 구조분해할당 

const [name, setName] = useState("루피")

name이라는 state 만들었고, name state의 처음값(initial state : 언제든지 변할 수 있는 값이기 때문에 존재)은 “루피”

 

State 변경하기

🌞onClick

setValue(바꾸고 싶은 값)를 사용 ( 아래에서는 setName )

import React, { useState } from "react";

function Third(props) {
  return (
    <div>
      <button
        onClick={() => {   // 여기에서 setName()을 실행
          props.setName("뽀로로");    // 드디어 받은 setName을 실행
        }}
      >
        루피 이름 바꾸기
      </button>
      <div>{props.PororoFriendsName}</div>
    </div>
  );
}

function Second(props) {
  return (
    <Third PororoFriendsName={props.PororoFriendsName} setName={props.setName} /> // 받아서 다시 주고
  );
}

function First() {
  const [name, setName] = useState("루피");
  return <Second PororoFriendsName={name} setName={setName} />; // 주고
}

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

export default App;

 

 

 

setName을 통해서 바꾼 값은 어디에 저장x => 단순히 화면에서만 바뀐 값으로 다시 렌더링(새로고침 시 초기값 나옴)

 

🌞useState + onClick Event

(1) Button과 이벤트 핸들러 구현하기

onClickHandler 라는 함수를 만들고 onClick={} 에 넣어주었다. React에서는 이러한 방식으로 함수와 컴포넌트(button 태그)를 연결. 이 함수를 이벤트 핸들러 라고 표현.

import React from "react";

function App() {
  // 버튼을 눌렀을 때 하고 싶은 행동 
  function onClickHandler() {
    console.log("hello button");
  }
  return (
    <div>
      <button onClick={onClickHandler}>버튼</button>
    </div>
  );
}

export default App;

(2) state 구현하고 이벤트 핸들러와 연결하기

state를 하나 만들고, 이 버튼을 클릭을 했을 때 state 값을 바꾼다.

이벤트 핸들러를 만들어주고 그 안에 setName 을 넣어줍니다.

이제 우리가 버튼을 누르면 setName()안에 있는 값이 “체리”이니까, state가 “사과"에서 “체리”로 바뀐다.

import React, { useState } from "react";

function App() {
  const [fruit, setFruit] = useState("사과");

  function onClickHandler() {
    setFruit("체리");
  }

  return (
    <div>
      {fruit}
      <button onClick={onClickHandler}>버튼</button>
    </div>
  );
}

export default App;

 

🌝 useState + onChange + Event

(1) Input과 state 구현하기

(2) 이벤트핸들러를 구현하고 state와 연결하기

이벤트 핸들러 안에서 자바스크립트의 event 객체를 꺼내 사용할 수 있다. 사용자가 입력한 input의 값은 event.target.value 로 꺼내 사용할 수 있다. 마지막으로 state인 value를 input의 attribute인 value에 넣어주면 input과 state 연결하기, 끝

import React, { useState } from "react";

const App = () => {
  const [value, setValue] = useState("");

  const onChangeHandler = (event) => {
    const inputValue = event.target.value;
    setValue(inputValue);
  };

	console.log(value) // value가 어떻게 변하는지 한번 콘솔로 볼까요?

  return (
    <div>
      <input type="text" onChange={onChangeHandler} value={value} />
    </div>
  );
};

export default App;

다시 설명하면 사용자가 input에 어떤 값을 입력하면, 그 값을 입력할 때마다, 같은 말로 onChange될 때마다 value라는 state에 setValue해서 넣어주는 것 이다.

 

import React, { useState } from "react";

const App = () => {
  const [fruit, setFruit] = useState("");

  return (
    <div>
    	과일 : {" "}
      <input 
      	value={fruit} 
     	 onChange={function (event) {
      		setFruit(event.targer.value)   
            // console.log('event', event.target.value)
      }} 
      />
     <br></br>
     {fruit}
    </div>
  );
};

export default App;

이벤트 핸들러 안에서 자바스크립트의 event 객체를 꺼내 사용할 수 있다

Event 객체 안에 있는 target 객체안에 value라는 값으로 우리가 타이핑 하는 것들이 들어온다. 매개변수로!

=> input의 값은 event.target.value

state인 value를 input의 attribute인 value에 넣어주면 input과 state 연결하기

 

사용자가 input에 어떤 값을 입력하면, 그 값을 입력할 때마다,

같은 말로 onChange될 때마다 value라는 state에 setValue해서 넣어주는 것

 

'React' 카테고리의 다른 글

React Hooks - useEffect  (0) 2023.04.19
React Component  (0) 2023.04.18
State 불변성  (0) 2023.04.15
Props, Props Children, Props 추출  (0) 2023.04.14
JSX(JavaScript + XML)  (0) 2023.04.14

+ Recent posts