react에서 date를 처리하는 것은 여간 까다로운 작업이 아닐 수 없습니다.

format을 다 처리해야 하기 때문이죠.

<input type='date' value='2022-04-09' />

react에서 input을 생성하고 type을 date를 줍니다.

date input value의 date format은 YYYY-MM-DD입니다.

const [date, setDate] = useState(new Date());

const getStringDate = (date) => {
  let year = date.getFullYear();
  let month = date.getMonth() + 1;
  let day = date.getDate();

  if (month < 10) {
    month = `0${month}`;
  }
  if (day < 10) {
    day = `0${day}`;
  }

  return `${year}-${month}-${day}`;
};

<input
  type='date'
  value={getStringDate(date)}
  onChange={(e) => {
    setDate(new Date(e.target.value));
  }} 
/ >

date를 받았을 때 YYYY-MM-DD 형식으로 리턴해주는 함수를 만들어줬습니다. ( 한입 크기로 잘라먹는 리액트(React.js) : 기초부터 실전까지 ) 참고하였습니다.

 

그리고 input value 에다가 date state를 삽입하고 onChange 에다가 setDate를 할 수 있는 콜백 함수를 넣어줍니다.

input date

정상적으로 잘 작동을 하는 것을 볼 수 있습니다.

useEffect(() => {
  console.log(date);
});

useEffect를 이용하여 date를 찍어보면 date 바뀔 때 즉 setDate 함수가 호출이 될 때 리 랜더링이 되며 console에 찍히는 걸 볼 수 있습니다.

 

기본으로 제공해주는 input date를 사용해도 가볍고 좋긴 한데 커스텀이 불편하다는 단점이 있습니다.

이걸 해결하기 위해 저는 DatePicker 라이브러리를 사용했습니다.

 

npm install react-datepicker --save

커맨드를 열고 npm으로 install 해줍니다.

import React, { useState } from 'react';
import DatePicker from 'react-datepicker';

function App() {
  const [startDate, setStartDate] = useState(new Date());

  <DatePicker
    selected={startDate}
    onChange={(date) => { 
      setDate(date); 
    }}
    className='date-picker'
  />
}

DatePicker component를 불러와주고 DataPicker에서는 value가 아니라 selected 속성을 넣어줍니다.

그리고 input date와는 다르게 따로 별로의 함수를 만들지 않아도 date를 자유롭게 사용할 수 있습니다.

 

그런데 이걸 이용하면 커스텀이 용이하다고 했는데 한번 css로 수정을 해보겠습니다.

.date-picker {
	border: 1px solid #b0a8b9;
	border-radius: 5px;
	text-align: center;
	width: 90px;
}

.date-picker:focus-visible {
	outline: none;
}

date-picker

아주 예쁘게 만들어진 모습을 볼 수 있습니다.

 

이상 data-picker 에 대해 공부한것을 포스팅 해보았습니다.

감사합니다

'FrontEnd > React' 카테고리의 다른 글

[ Optimize ] useCallback  (0) 2022.04.05
[ Optimize ] useMemo  (0) 2022.04.04
[ Optimize ] React.memo  (0) 2022.04.04
[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useEffect  (0) 2022.03.27

useMemo 에 이어서 useCallback 에 대해서 알아봅시다.

이번에도 Dingdong Ditch(띵똥 벨튀) component를 뜯어서 개조를 해볼것입니다.

 

전 포스팅에서도 말했지만 useMemo, useCallback 서로비슷합니다.

useMemo 기반에서 추가된게 useCallback 이니까영

 

Memoization 이란? 

주어진 입력값에 대한 결과를 저장함으로써 같은 입력값에 대해 함수가 한 번만 실행되는 것을 보장을 의미합니다.

 

useMemo:   memoization  값을 반환 합니다.

useCallback: memoization  함수를 반환 합니다.

 

useCallback의 간단한 예시를 들자면

1.  useCallback(() => fn, [deps]);  // deps의 데이터가 변하게 된다면

2.  useCallback(() => fn, [deps]);  // callback 함수를 반환 하게 됩니다.

 

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

const Bell202 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell202');
  });

  return <div>{`Bell 202!! ${call}`}</div>;
});

const Bell402 = React.memo(({ ditch, call }) => {
  useEffect(() => {
    console.log('Rerender Bell402');
  });

  return (
    <>
      <div>{`Bell 402!! ${call}`}</div>
      <button onClick={ditch}>Bell 402</button>
    </>
  );
});



const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call402, setCall402] = useState(0);

  const ditch = () => {
    setCall402(call402 + 1);
  };

  return (
    <div>
      <Bell202 call={call202} />
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>
      <Bell402 call={call402} ditch={ditch} />
    </div>
  );
};

export default DingdongDitch;

402호 --> 202호
console

202호 벨을 눌렀는데 402호도 rerender 가 되는것을 볼 수 있습니다.

분명 React.memo()를 적용했는데 왜 이런 현상이 일어나는걸까요?

 

React.memo에 대해 모르신다면 해당 포스팅을 봐주세영!

call402 state가 값이 변하기 때문에 상위 컴포넌트에서 Re-Rendering 이 발생하고 props에 들어온 ditch 함수가 계속 재선언이 되기 때문 입니다.

 

import React, { useState, useEffect, useCallback } from 'react';

const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call402, setCall402] = useState(0);

  const ditch = useCallback(() => {
    setCall402(call402 + 1);
  }, [call402]);

  return (
    <div>
      <Bell202 call={call202} />
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>
      <Bell402 call={call402} ditch={ditch} />
    </div>
  );
};

export default DingdongDitch;

 

ditch 함수를 useCallback으로 감싸서 함수를 넘겨줬더니 202호 벨을 눌렀지만 402호 벨은 Re-Rendering이 발생하지 않는걸 볼수있습니다.

 

간단하게 예제와 함께 설명을 해보았습니다.

여기까지 봐주신 여러분 감사합니당

 

'FrontEnd > React' 카테고리의 다른 글

Input - Date, DatePicker library 📅  (0) 2022.04.09
[ Optimize ] useMemo  (0) 2022.04.04
[ Optimize ] React.memo  (0) 2022.04.04
[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useEffect  (0) 2022.03.27

useMemo

useMemo에 대해 공부를 하였지만 어떤 예제를 들어야 할지 애매모호 해서 상당히 골치 아팠습니다.

그러다 어제 올린 React.memo 에서 띵똥 벨튀 예제를 가져와서 쓰면 괜찮을것 같아서 DindongDitch를 개조해 보았습니다.

 

useMemo 를 공부하면 useCallback 은 필연으로 공부를 하게 됩니다.

두가지 비슷하지만 확연히 차이가 있습니다.

 

Memoization 이란? 

주어진 입력값에 대한 결과를 저장함으로써 같은 입력값에 대해 함수가 한 번만 실행되는 것을 보장을 의미합니다.

 

useMemo:   memoization값을 반환 합니다.

useCallback: memoization함수를 반환 합니다.

 

useMemo의 간단한 예시를 들자면

1.  useMemo(() => fn, [deps]);  // deps의 데이터가 변하게 된다면

2.  useMemo(() => fn, [deps]);  // callback 함수가 실행 된 값을 반환 하게 됩니다.

 

[ deps ] 저 부분은 dependency ( 의존 ) 이라는 의미이며 저 데이터가 변할때마다 callback 함수실행 된 값 반환 받게 됩니다.

 

// study React.memo

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

const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call303, setCall303] = useState(0);
  const [call402, setCall402] = useState(0);

  const getTotalBell202303 = () => {
    console.log('define totalBell202303');

    return call202 + call303;
  }

  const totalBell202303 = getTotalBell202303();

  return (
    <div>
      <span>Bell202 + Bell303: {totalBell202303}</span> <br/>
      <Bell202 call={call202}/>
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>

      <Bell303 call={call303}/>
      <button onClick={() => setCall303(call303 + 1)}>Bell 303</button>

      <Bell402 call={call402}/>
      <button onClick={() => setCall402(call402 + 1)}>Bell 402</button>
    </div>
  )
}

export default DingdongDitch;

402호 --> 303호 --> 202호
console

202호, 303호 벨 눌렀던 횟수를 합치는 함수 getTotalBell202303() 를 만들고 변수 totalBell202303 에다가 데이터를 받습니다.

totalBell202303가 선언 될때 console로 뜨게 했습니다.

 

분명 402호 벨을 눌렀는데 totalBell202303 변수가 계속 선언이 되고 있습니다.

402호 state가 값이 변할때 Component Re-Rendering이 발생하는건데 그래서 totalBell202303 변수가 계속하여 재선언이 되고 있던것입니다.

 

 

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

const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call303, setCall303] = useState(0);
  const [call402, setCall402] = useState(0);

  const getTotalBell202303 = () => {
    console.log('define totalBell202303');

    return call202 + call303;
  }

  const totalBell202303 = useMemo(getTotalBell202303, [call202, call303]);

  return (
    <div>
      <span>Bell202 + Bell303: {totalBell202303}</span> <br/>
      <Bell202 call={call202}/>
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>

      <Bell303 call={call303}/>
      <button onClick={() => setCall303(call303 + 1)}>Bell 303</button>

      <Bell402 call={call402}/>
      <button onClick={() => setCall402(call402 + 1)}>Bell 402</button>
    </div>
  )
}

export default DingdongDitch;

402호 --> 303호 --> 202호
console

const totalBell202303 = useMemo(getTotalBell202303, [call202, call303]);

 

useMemo의 첫 번째 인자는 callback 함수와 두번째 인자는 dependency(의존) 변수를 넣어줍니다.

그렇게 의존성 부분의 데이터가 변할때만 으로 할당이 되어 totalBell202303 변수가 component에 의해 리랜더링 될 때 마다 재선언 하는 일이 없어집니다.

 

이상 useMemo에 관한 이야기를 해보았습니다.

여기까지 따라와주신 여러분 수고하셧습니다.

 

비고) Bell202, Bell303, Bell402 컴포넌트는 코드가 너무 길어져 아래에 넣어두겠습니다.

더보기
const Bell202 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell202');
  });

  return <div>{`Bell 202!! ${call}`}</div>
});

const Bell303 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell303');
  });

  return <div>{`Bell 303!! ${call}`}</div>
});

const Bell402 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell402');
  })

  return <div>{`Bell 402!! ${call}`}</div>
});

'FrontEnd > React' 카테고리의 다른 글

Input - Date, DatePicker library 📅  (0) 2022.04.09
[ Optimize ] useCallback  (0) 2022.04.05
[ Optimize ] React.memo  (0) 2022.04.04
[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useEffect  (0) 2022.03.27

React 최적화를 하기 위해 useMemo, React.memo, useCallback 세가지를 보통 이용 합니다 (제가 아직 배운게 이것밖에 없어서)

 

그중에서 React.memo에 대해 공부하며 예제를 간단히 만들어보며 연구를 했는데

괜찮은 예제가 떠올라서 이렇게 공부한걸 올리는 겸 예제를 공유 해봅니다.

 

React.memo를 배우기전에 Memoized에 대해서 알아야하는데 Memoized는 주어진 입력값에 대한 결과를 저장함으로써 같은 입력 값에 대해 함수가 한 번만 실행되는 것을 보장하는것을 의미합니다. ( 알고리즘 방식이기도 합니다. )

 

React.memoComponent의 결과값Memoized를 합니다

띵동!


한국에서 어릴때 유행했던 벨튀(DingDong Ditch) 를 바탕으로 Component 화 시켜서 만들어본 예제 입니다. 

// study React.memo

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

const Bell202 = ({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell202');
  });

  return <div>{`Bell 202!! ${call}`}</div>
};

const Bell303 = ({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell303');
  });

  return <div>{`Bell 303!! ${call}`}</div>
};

const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call303, setCall303] = useState(0);

  return (
    <div>
      <Bell202 call={call202}/>
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>

      <Bell303 call={call303}/>
      <button onClick={() => setCall303(call303 + 1)}>Bell 303</button>
    </div>
  )
}

export default DingdongDitch;

설명을 하기 위한 그림
Click Button
Console

아파트가 하나 있고 202호 벨을 누르고 튀었습니다.
그런데 303호 벨도 같이 울립니다.
 
Ball202 state 값이 변했기 때문에 Component Re-Rendering 현상발생한 것인데

상위 컴포넌트인 DingdongDitch state 값이 변하여 Re-Rendering이 되면서
하위 컴포넌트인 Bell303 ComponentRe-Rendering이 되어버립니다.

 

Component가 Re-Rendering이 되는 기준
1. 새로운 props가 들어오거나 (업데이트)
2. 부모 컴포넌트가 Re-Rendering이 되었을때
 

부모 컴포넌트가 Re-Rendering이 되면서 데이터가 바뀌며 202호 벨(props)를 눌렀지만 303호 벨 까지 눌러지는 상황이 발생이 된겁니다. 또한 303호 벨을 누르자 202호 벨까지 울리게 되는거죠.

 

rerender 기준의 2번째인 부모 컴포넌트가 re-rendering이 되었기 때문인데 이런경우 React.memo를 이용하여 Component를 감싸면 의미없는 Re-Rendering 이 해결이 됩니다.

 

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

const Bell202 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell202');
  });

  return <div>{`Bell 202!! ${call}`}</div>
});

const Bell303 = React.memo(({ call }) => {
  useEffect(() => {
    console.log('Rerender Bell303');
  });

  return <div>{`Bell 303!! ${call}`}</div>
});

const DingdongDitch = () => {
  const [call202, setCall202] = useState(0);
  const [call303, setCall303] = useState(0);

  return (
    <div>
      <Bell202 call={call202}/>
      <button onClick={() => setCall202(call202 + 1)}>Bell 202</button>

      <Bell303 call={call303}/>
      <button onClick={() => setCall303(call303 + 1)}>Bell 303</button>
    </div>
  )
}

export default DingdongDitch;

 

설명을 하기 위한 그림
Button Click

React.memo를 이용하여 Component를 감싸면 상위 Component가 Re-Rendering이 되었다 해도 props가 동일하다면 바꾸지 않습니다.

 

이상 띵똥 벨튀를 이용한 예시였습니다.

감사합니다.

'FrontEnd > React' 카테고리의 다른 글

[ Optimize ] useCallback  (0) 2022.04.05
[ Optimize ] useMemo  (0) 2022.04.04
[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useEffect  (0) 2022.03.27
React - useRef DOM 제어  (0) 2022.03.25

RRD ( React - Router - Dom ) 이란?

리액트 라우터는 화면 전환을 도와주는 역할
웹에서 a tag를 통해 다른 페이지로 이동한다면,
React에서는 React-Router을 통해 Link 태그를 사용하여 화면을 전환합니다.

 

일반적으로
웹에서 a tag를 통해서 새로고침이 되며 이동하는걸 MPA (Multi Page Application)이라고 하고
React 같은 경우를 SPA(Single Page Application, CSR(Cliend Side Rendering)이라고 합니다.


BrowserRouter 이란?

  1. Link Component를 to 속성에 이동할 경로를 작성
  2. Route Component path 속성을 Link의 to 속성과 매핑 component의 컴포넌트 경로 기술
  3. 새로고침을 하면 경로를 찾지 못하여 에러를 발생
  4. History Api 사용

install Router Module

cmd 또는 powershell을 열어서 다음과 같이 설치를 해줍니다.

npm install react-router-dom@6

import Router

react-router-dom 모듈을 가져옵니다.

// import Router
import { BrowserRouter, Route, Routes } from "react-router-dom";

Browser Router

기본 구조는 최상단 Element를 <BrowserRouter> component가 감싸게 됩니다.

Route

최상단 element 아래 위치하게 되며 <Routes> 태그가 <Route> 태그를 감싸는 형태이며 <Route> 태그는

path와 element 속성을 가지고 있습니다.


path 속성은 경로 url을 적는 공간이며
element 속성은 보여줄 component를 적는 공간입니다.

 

 

 

github에 Markdown으로 정리를 해두었습니다. ( 내용은 동일 )

 

https://github.com/GangOn0215/dev-til/blob/main/React/Router.md

'FrontEnd > React' 카테고리의 다른 글

[ Optimize ] useMemo  (0) 2022.04.04
[ Optimize ] React.memo  (0) 2022.04.04
React - useEffect  (0) 2022.03.27
React - useRef DOM 제어  (0) 2022.03.25
React & Node.js 연동하기  (0) 2022.03.24

React 하면서 가장 중요하다고도 할수있는 LifeCycle useEffect 에 대해 공부한대로 한번 글을 써볼 예정 입니다.

 

React Component의 LifeCycle (생명 주기) 라고 하는것은  Mount ( 탄생 ) --> Update ( 변화 ) --> UnMount ( 죽음 )  이라고 하는데요.

 

Mount는 즉 Component가 생성 되었을때 최초 한번 실행이 되는것이며

Update는 Component가 리랜더링 될때마다 실행이 되는것이며

UnMount는 Component가 없어지거나 사라질때 실행이 되는것입니다.

 

각각 상황에 따라 useEffect를 사용할수있는데 보통 Mount 즉 Component 가 Mount가 될때 초기화를 보통 시킵니다.

useEffect(() => {
  // todo...
}, []);

useEffect 의 기본적인 코드부터 보겠습니다.

 

안에 보시면 //todo.. 라고 되어 있는곳이 callback 함수 이고 [] 빈 배열이 있는 부분이 Dependency Array (의존성 배열) 입니다.

 

배열 내에 들어있는 값이 변화하면 콜백 함수가 실행됩니다.

 

import React from "react";
import LifeCycle from "./Components/LifeCycle";

const App = () => {
  <LifeCycle />
}

export default App;
import React, {useEffect} from "react";

const LifeCycle = () => {
  useEffect(() => {
    console.log("Mount!");
  }, []);

  return (<div></div>)
}

export default LifeCycle;

이제 본격적으로 코드를 적어볼것인데 Mount부터 해보겠습니다.

 

일단 LifeCycle Component를 만들어 App Component에 올려둡니다.

기본적으로 useEffect 를 불러온뒤 다음과 같이 코드를 짜게 되면 Component가 처음 생성될때 한번만 실행을 하게 됩니다. 보통 초기화를 할때 많이 사용합니다.

 

 useEffect Mount 

import { useEffect, useState } from "react";

function LifeCycle() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Mount!");
  }, []);

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

  return (
    <div className="LifeCycle">
      {count}
      <button onClick={() => { setCount(count + 1); }}>
        add count
      </button>
    </div>
  );
}

export default LifeCycle;

LifeCycle Update를 해보겠습니다.

 

Mount 확인을 할때는 useEffect 뒤에 Dependency, 빈배열을 붙였지만 만약에 붙이지 않는다면 컴포넌트가 리랜더링 될때마다 update 부분 의 함수가 호출이 되게 됩니다.

 

useEffect Update

 

import { useEffect, useState } from "react";

function LifeCycle() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Mount!");
  }, []);

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

  return (
    <div className="LifeCycle">
      {count}
      <button onClick={() => { setCount(count + 1); }}>
        add count
      </button>
    </div>
  );
}

export default LifeCycle;

간단한 count 프로그램을 만들어 테스트를 해보겠습니다. 

 

count 변수를 만든뒤 버튼을 클릭하면 setCount를 통해서 count 값이 올라가는 프로그램 입니다.

클릭할때마다 console log에서 Update가 찍혀나오는걸 볼수있습니다.

 

state의 값이 바뀌기 때문에 component가 리랜더링이 되게 되고 Dependency 없는 useEffect의 콜백 함수가 실행되게 됩니다.

 

import { useEffect, useState } from "react";

function LifeCycle() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState("");

  useEffect(() => {
    console.log("Mount!");
  }, []);

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

  useEffect(() => {
    console.log(`count up ${count}`);
  }, [count]);

  useEffect(() => {
    console.log(`text change ${text}`);
  }, [text]);

  return (
    <div className="LifeCycle">
      <div>
        {count}
        <button onClick={() => { setCount(count + 1); }}>
          add count
        </button>
      </div>
      <div>
        {text}
        <input value={text} onChange={(e) => setText(e.target.value)} />
      </div>
    </div>
  );
}

export default LifeCycle;

이제 빈 배열에 state를 넣어 해당 state가 값이 변할때만 실행하는 useEffect를 만들어 보겠습니다.

 

count 버튼을 클릭하여 onClick 이벤트가 발생하여 setCount(count + 1) 함수가 실행이 되어 count state가 바뀌고

콜백함수가 실행되게 됩니다.

 

 

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

const UnMountTest = () => {

  useEffect(() => {
    console.log('Mount');

    return() => {
      console.log('UnMount');
    }
  }, []);

  return (
    <span> UnMount Test </span>
  )
}

const LifeCycle = () => {
  const [isToggle, setIsToggle] = useState(false);
  const handleToggle = () => {
    setIsToggle(!isToggle);
  }

  return (
    <div>
      <button onClick={handleToggle}>Toggle</button>
      { isToggle && <UnMountTest/> } 
    </div>
  )
}

export default LifeCycle;

이제 마지막으로 UnMount에 대해서 알아볼겁니다.

Mount 는 Component가 생성 될때 처음 실행이 된다면 UnMount는 Component가 없어지거나 사라질때 실행이

됩니다.

 

다음 코드는 생소한 코드를 보셧을수도 있겠습니다. isToggle && <UnMountTest /> 인데 해당 코드는 단락회로 평가 라는것입니다.

 

 useEffect Delete 

이제 버튼을 클릭하면 unmount 텍스트가 생기고 사라지는데 console 에서 Component가 생성될때 Mount, 없어질때 UnMount가 console 창에 찍히는걸 볼수있습니다.

 

지금까지 uesEffect 의 Mount Update UnMount 에 대해 혼자 공부하는겸 포스팅 해보았습니다.

 

감사합니당.

 

'FrontEnd > React' 카테고리의 다른 글

[ Optimize ] React.memo  (0) 2022.04.04
[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useRef DOM 제어  (0) 2022.03.25
React & Node.js 연동하기  (0) 2022.03.24
React - Props  (0) 2022.03.23

리액트를 공부하다 보면 uesRef를 공부하게 될건데 useRef 는 JavaScript를 사용할때,

특정 DOM 을 컨트롤하기 위해 사용합니다,

주로 vanillaJS에서 document.querySelector, document.getElementById 와 같은것입니다.

 

간단한 예제를 보면서 확인을 해보도록 할게요.

 

import { useState, useRef } from "react";

function App() {
  const [userID, setUserID] = useState("");
  const [userPW, setUserPW] = useState("");

  const handleChangeID = (e) => {
    setUserID(e.target.value);
  };

  const handleChangePW = (e) => {
    setUserPW(e.target.value);
  };
  
  const handleSubmit = () => {
    console.log("userID: ", userID);
    console.log("userPW: ", userPW);
  };

  return (
    <div className="App">
      <input
        name="userID"
        value={userID}
        onChange={handleChangeID}
      />
      <input
        name="password"
        value={userPW}
        onChange={handleChangePW}
        type="password"
      />
      <button onClick={handleSubmit}>Login</button>
    </div>
  );
}

export default App;

간단한 id, pw를 받아서 로그인을 하는 프로그램을 만들어 보았습니다.

그런데 userID userPW 두가지 인데 상당히 코드양이 많은것을 확인 할수있습니다.


 

import { useState, useRef } from "react";

function App() {
  const [account, setAccount] = useState({
    userID: "",
    userPW: "",
  });

  const handleChangeAccount = (e) => {
    setAccount({
      ...account,
      [e.target.name]: e.target.value,
    });
  };

  const handleSubmit = () => {
    console.log("Account info: ", account);
  };

  return (
    <div className="App">
      <input
        name="userID"
        value={account.userID}
        onChange={handleChangeAccount}
      />
      <input
        name="userPW"
        value={account.userPW}
        onChange={handleChangeAccount}
        type="password"
      />
      <button onClick={handleSubmit}>submit</button>
    </div>
  );
}

export default App;

여러개의 input 상태를 관리하는 방법으로 수정해 보겠습니다.

그리고 handleChangeID, handleChangePW 함수 또한 합쳐보도록 하겠습니다.

 

다음과 같이 사용성이 아주 용이하게 바뀐 코드를 보실수 있습니다.

  const inputUserID = useRef();
  const inputUserPW = useRef();

이제 useRef를 사용하여보겠습니다.

 

jsx의 return 문 밖에서  다음과 같이 코드를 만들어 줍니다.

그리고 return 안에 input 부분에서 ref 속성을 추가해 줍니다.

<input
  ref={inputUserID}
  name="userID"
  value={account.userID}
  onChange={handleChangeAccount}
/>
<input
  ref={inputUserPW}
  name="userPW"
  value={account.userPW}
  onChange={handleChangeAccount}
  type="password"
/>

다음과 같이 ref={} 이러한 속성을 넣어주면 됩니다.

 

이제 useRef를 이용하여 DOM 을 컨트롤 해볼것입니다.

const handleSubmit = () => {
    if (account.userID < 5) {
      return; 
    }

    if (account.userPW < 8) {
      return;
    }

    console.log("Account info: ", account);
};

다음과 같이 userID 데이터 길이가 5개 미만 일때, userPW 데이터 길이가 8개 미만 일때

alter보다 focus를 줘서 유저에게 확인을 해주고 싶다면, useRef 를 사용하여 제어하면 됩니다.

 

  const handleSubmit = () => {
    if (account.userID.length < 5) {
      inputUserID.current.focus();

      return;
    }

    if (account.userPW.length < 8) {
      inputUserPW.current.focus();

      return;
    }

    console.log("Account info: ", account);
};

이제 userID 데이터 길이가 5미만 일때, userPW 길이가 8미만 일때 각각 focus가 작동되어 해당 조건이 실행 될때 해당 input창이 깜빡 깜빡 거리는것을 볼수있습니다.

 

 

이런식으로 React 에서도 Dom을 조작하여 재밌는것들을 만들어 보면 좋을것 같습니다.

 

고생하셧습니당

'FrontEnd > React' 카테고리의 다른 글

[ RRD ] React - Router - Dom  (0) 2022.03.31
React - useEffect  (0) 2022.03.27
React & Node.js 연동하기  (0) 2022.03.24
React - Props  (0) 2022.03.23
React - State  (0) 2022.03.18

이 포스트를 쓰기 전에 여러 블로그 포스트를 보고 왔습니다.

 

https://velog.io/@autumndr3ams/210802-React-Node.jsexpress-연결하기

https://baegofda.tistory.com/210

https://baegofda.tistory.com/211

 

일단 Node.js 가 설치되어 있다는 가정하에 진행을 하겠습니다.

 

1. 일단 작업 할 폴더(testReact)를 만든 뒤 cmd 또는 파워쉘을 키고 npx create-react-app client 를 쳐줍니다.

다음과 같이 나왔다면 제대로 설치된 것 입니다.

 

2. 그럼 폴더에 client 폴더가 있을건데 전 testReact 라는 폴더에 만들었으니 testReact 라는 폴더안에서 커맨드 창을 열고 server을 설치해줄겁니다.

 

일단 npm init 명령어를 친 다음 설정하신후 

npm install express 명령어를 쳐줍니다.

 

testReact 폴더 안에 server 라는 폴더를 만든 뒤 server 폴더 안에 server.js , Router 폴더와 api.js 를 만들어 줍니다.

그럼 폴더 구조가 이런식으로 될것입니다.

그리고 이제 코드를 작성할건데

 

server.js

const express = require("express");
const app = express();

const api = require("./Router/api");

app.use(express.json());
app.use("/api", api);

const port = 5000;

app.listen(port, () => {
  console.log(`Listening on port ${port}`);
});

 

Router/api.js

const express = require("express");
const router = express.Router();

router.get("/", (req, res) => {
  res.send({ api: "Welcome Hell" });
});

module.exports = router;

 

그리고 이제 server 쪽을 테스트 해볼것입니다.

 

node 명령어가 기본탑재 인데 불편한 부분이 있습니다.

업데이트 할때마다 서버를 껏다 킬수가 없기에 nodemon을 설치해줍니다.

 

그리고 concurrently 를 설치해줍니다.

concurrently 는 react 서버와 node 서버를 동시에 실행 시키기 위한 모듈 입니다.

 

npm install nodemon --save

npm install concurrently --save

 

그 뒤에 package.json에서 다음 scripts를 추가 해줍니다.

 

{
  "name": "testreact",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "server": "cd server && nodemon server",
    "client": "cd client && npm start",
    "start": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\""
  },
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "concurrently": "^7.0.0",
    "express": "^4.17.3",
    "nodemon": "^2.0.15"
  }
}

저장후 npm start를 해줍니다.

 

localhost:3000 , localhost:5000 으로 접속을 하여 문제가 없는지 확인해줍니다.

그리고 주소창에 localhost:5000/api 를 친다음 화면에 {"api": "Welcome Hell"} 이라고 나오면 정상적으로 작동하고 있는것입니다.

 

이제 client폴더에 가서 cmd 창을 열고 npm install http-proxy-middleware --save 를 쳐줍니다.

그리고 react에서 node.js와 통신을 하기 위해 axios를 설치해줍니다. npm install axios --save

그리고 코드를 수정해줍니다.

 

/client/src/App.js

import axios from "axios";
import { useEffect } from "react";

function App() {
  const callApi = async () => {
    axios.get("/api").then((res) => {
      console.log(res.data.api);
    });
  };

  useEffect(() => {
    callApi();
  }, []);

  return <div className="App"></div>;
}

export default App;

그리고 /client/src/setupProxy.js를 생성후

const { createProxyMiddleware } = require("http-proxy-middleware");

const apiUrl = "http://localhost:5000/";
const apiContext = ["/api"];

module.exports = (app) => {
  app.use(
    createProxyMiddleware(apiContext, {
      // 도메인 api로 호출
      target: apiUrl, // 통신할 서버의 도메인 주소
      changeOrigin: true,
    })
  );
};

다음과 같이 코드를 적어줍니다.

 

지금까지 했던것을 폴더 구조로 확인하자면 이런 형태가 나오게 됩니다.

 

 

그럼 console 창에서 Welcome Hell 이 나오는것을 볼수있습니다.

'FrontEnd > React' 카테고리의 다른 글

React - useEffect  (0) 2022.03.27
React - useRef DOM 제어  (0) 2022.03.25
React - Props  (0) 2022.03.23
React - State  (0) 2022.03.18
React 왜 배우는 것 일까?  (0) 2022.03.17

보통 처음에 state를 배우고 나면 props 개념을 배우게 됩니다.

 

props는 보통 상단 componet에서 하단 component에게 이름을 붙여 값을 전달하는 방식이며

여러 데이터를 넘길수 있습니다.

 

Props를 사용하는 이유는 상단 컴포넌트에서 하단 컴포넌트에게 데이터를 이동시켜주기 위함입니다.

 

App.js

import React from "react";

import MyHeader from "./components/MyHeader";
import Counter from "./components/Counter";

function App() {
  return (
  	<div className="app">
    	<Counter initialValue={5} />
    </div>
  );
}

export default App;

 

Counter.js

import React, { useState } from "react";

const Counter = (props) => {
  console.log(props); // { initialValue: 5 }
};

export default Counter;

props 는 매개변수로 받아오며 console.log를 찍어보면 initialValue를 가진 object 받아오게 됩니다, 그래서

 


 

App.js

import React from "react";

import MyHeader from "./components/MyHeader";
import Counter from "./components/Counter";

function App() {
  return (
  	<div className="app">
    	<Counter a={1} b={2} initialValue={5} />
    </div>
  );
}

export default App;

a={1} b={2} initalValue={5} 이러한 형태로 데이터를 넘겨준다면 

Counter.js

import React, { useState } from "react";

const Counter = (props) => {
  console.log(props); // { a: 1, b: 2, c: 3, initialValue: 5 }
};

export default Counter;

Counter Component에서는 a, b, initialValue를 가지고 있는 object 데이터를 받게 됩니다.

{ a: 1, b: 2, initialValue: 5 }

App.js

import React from "react";

import Counter from "./components/Counter";

function App() {
  const counterProps = {
    a: 1,
    b: 2,
    c: 3,
    initialValue: 5,
  };

  return (
    <div className="app">
      <Counter {...counterProps} />
    </div>
  );
}

export default App;

만약 데이터 넘기는 양이 많아진다면 Spread Operator (스프레드 연산자)를 사용할 수도 있습니다.

Spread Operator (스프레드 연산자)는 특정 객체 또는 배열의 값을 다른 객체, 배열로 복제하거나 옮길 때 사용됩니다.

 

Counter.js

import React, { useState } from "react";

const Counter = (props) => {
  console.log(props); // { a: 1, b: 2, c: 3, initialValue: 5 }
};

export default Counter;

console을 찍어보게 되면 바로 전 코드와 같이 직접 대입하는 방식과 같은 결과가 나오게 됩니다.

 

만약 props에서 [ a, initialValue ]만 뽑아오고 싶다면 어떻게 하면 가져올 수 있을까요?

바로 ES6(2015)에 추가된 Destructuring Assignment (비 구조화 할당)을 사용하면 됩니다.


Counter.js

import React, { useState } from "react";

const Counter = ({a, initialValue}) => {
  console.log(a);            // 1
  console.log(initialValue); // 5
};

export default Counter;

 

Destructuring Assignment(비 구조화 할당)로 받은 데이터를 확인해보면 데이터가 잘 넘어온 것을 확인할 수 있습니다.

 

만약 propsundefined가 들어있다면 문제가 발생하는데 그것을 해결하는 걸 해보도록 할게요.

 

App.js

import React from "react";

import Counter from "./components/Counter";

function App() {
  const counterProps = {
    a: 1,
    b: 2,
    c: 3,
  };

  return (
    <div className="app">
      <Counter {...counterProps} />
    </div>
  );
}

export default App;

이런 식으로 counterProps에서 initialValue를 지우고 데이터를 넘겨준다면


Counter.js

import React, { useState } from "react";

const Counter = ({a, initialValue}) => {
  console.log(initialValue); // undefined
};

export default Counter;

이런 식으로 undefiend 가 뜨게 됩니다, 이런것을 방지하기 위해 defaultProps라는것이 있는데

 

Counter.js

import React, { useState } from "react";

const Counter = ({ initialValue }) => {
  console.log(initialValue); // 0
};

Counter.defaultProps = {
  initialValue: 0,
};

export default Counter;

이런식으로 defaultProps를 지정하게 되면 props를 받아올 때 만약 데이터가 없다면 0으로 초기화를 시켜줄 수 있습니다.

 

이상으로 props에 대한 이야기를 해보았습니다.

아직 많이 부족하지만 공부 한것을 정리할겸 포스팅 해보았습니다.

만약 부족하거나 잘못된 점을 말씀해주시면 바로바로 수정하겠습니다.

 

감사합니당.

더보기

해당 포스트는 Inflearn의 한입 크기로 잘라 먹는 리액트(React.js) 강의를 보고 참고 하였습니다.

 

'FrontEnd > React' 카테고리의 다른 글

React - useEffect  (0) 2022.03.27
React - useRef DOM 제어  (0) 2022.03.25
React & Node.js 연동하기  (0) 2022.03.24
React - State  (0) 2022.03.18
React 왜 배우는 것 일까?  (0) 2022.03.17

전에 봤던 vanilla js 의 counter 프로그램을 React로 만든다고 한다면,

 

App.js

import React from "react";
import Counter from "./components/Counter"

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

export default App;

기본적으로 Counter 이라는 Component 를 이용하여 count increment, decrease 를 하는 코드를 만들어 볼것입니다.

 

Component.js

import React, { useState } from "react";

const Counter = () => {
  const [count, setCount] = useState(0);

  const onIncrease = () => {
    setCount(count + 1);
  };

  const onDecrease = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h2>{count}</h2>
      <button onClick={onIncrease}>+</button>
      <button onClick={onDecrease}>-</button>
    </div>
  );
};

export default Counter;

userState 함수를 불러오게 되어 count, setCount 라는 state를 활용하여 데이터를 수정하게 되고

vanilla js로 짠 코드보다 훨씬 간결하고 가독성이 좋아진 것을 볼 수 있습니다.

 

 

inflearn의 한입-리액트 강좌를 보고 많이 참고 했습니다.

'FrontEnd > React' 카테고리의 다른 글

React - useEffect  (0) 2022.03.27
React - useRef DOM 제어  (0) 2022.03.25
React & Node.js 연동하기  (0) 2022.03.24
React - Props  (0) 2022.03.23
React 왜 배우는 것 일까?  (0) 2022.03.17

+ Recent posts