โš›๏ธReact

React๋Š” ๋ฌด์—‡์ธ๊ฐ€

  • Facebook์—์„œ ๋งŒ๋“  ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ

  • ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค(UI)๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ์„ ์–ธํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ, ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜

  • ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์š”์†Œ๋ฅผ ํ†ตํ•ด UI๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋นŒ๋“œ

React๋Š” ์™œ ์ƒ๊ฒผ๋‚˜

  • ํ…œํ”Œ๋ฆฟ, HTML ์ง€์‹œ๋ฌธ์ด ์•„๋‹Œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ†ตํ•œ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ

    • ๋งˆํฌ์—…๊ณผ ๋ทฐ ๋กœ์ง์˜ ํ†ตํ•ฉ

    • ๋งˆํฌ์—…๊ณผ์˜ ์—ฐ๊ฒฐ ๋ถˆํ•„์š”

  • ๋ณต์žกํ•œ ๋ฆฌ๋ Œ๋”๋ง ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ

    • render ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๊ฐ„ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์ง‘ํ•˜์—ฌ ํšจ์œจ์  ์—…๋ฐ์ดํŠธ

React ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ํ•˜๊ธฐ

  • ๊ธฐ๋ณธ ์ฃผ์†Œ: localhost:3000

  • react ์•ฑ ์‹œ์ž‘ํ•˜๊ธฐ

npx	create-react-app [project-name]
  • ๊ฐœ๋ฐœ์šฉ CDN ๋งํฌ

<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  • ๋ฐฐํฌ์šฉ CDN ๋งํฌ

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

React ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

  • /public

  • /node_modules

  • /src

    • App.js

    • index.js

    • index.css

  • .gitignore

  • package.json

  • README.md

React ๊ฐœ๋ฐœ์ž ๋„๊ตฌ

๋ฆฌ์•กํŠธ ๋””๋ฒ„๊น… ํˆด

https://github.com/facebook/react/tree/main/packages/react-devtools-extensions

JSX

  • JavaScript๋ฅผ ํ™•์žฅํ•œ ๋ฌธ๋ฒ•์œผ๋กœ์„œ React์—์„œ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

  • html์„ jsx๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์‚ฌ์ดํŠธ https://transform.tools/html-to-jsx

JSX ์—์„œ ํ‘œํ˜„์‹ ๋„ฃ๊ธฐ

  • {} ์ค‘๊ด„ํ˜ธ ์•ˆ์—์„œ๋Š” JavaScript ํ‘œํ˜„์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const name = 'John';
const element = <h1>My name is {name}</h1>;

JSX์—์„œ ์†์„ฑ ๋„ฃ๊ธฐ

  • ์†์„ฑ={๊ฐ’} ์†์„ฑ="๋ฌธ์ž์—ด" ํ˜•ํƒœ

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋กœ์ง๊ณผ ๋ณ€์ˆ˜๋ฅผ ๋งˆํฌ์—…์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

const color = "red"
const element = <h1 color="red">My name is {name}</h1>;
const element = <h1 color={color}>My name is {name}</h1>;

์†์„ฑ๋ช…์€ CamelCase๋ฅผ ์‚ฌ์šฉ

์†์„ฑ ๋ช…์€ CamelCase๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑ(onclick -> onClick)

// โŒ
<button onclick={handleClick}></button>
// โœ… CamelCase ์‚ฌ์šฉ
<button onClick={handleClick}></button>

๋ชจ๋“  ํƒœ๊ทธ๋Š” ๋‹ซํ˜€์•ผ ํ•œ๋‹ค

// โŒ
<br>
<img>
<input>
<li>
// โœ…
<br/>
<img/>
<input/>
<input></input>
<li>

Fragment

์ตœ์ƒ์œ„ ์š”์†Œ๋Š” ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.

์ตœ์ƒ์œ„ ์š”์†Œ๋ฅผ 2๊ฐœ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ๋Š” ์˜๋ฏธ ์—†๋Š” divํƒœ๊ทธ ๋ณด๋‹ค๋Š” <></> Fragment๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์‹ผ๋‹ค.

// โŒ ์ตœ์ƒ์œ„ ์š”์†Œ๊ฐ€ 2๊ฐœ์ด๋‹ค.
<header>
    <nav></nav>
</header>
<section>
    <ul>
	    <li></li>
    	<li></li>
    </ul>
</section>
// โŒ ์ตœ์ƒ์œ„ ์š”์†Œ๊ฐ€ 2๊ฐœ์ด๋‹ค.
<>
<header>
    <nav></nav>
</header>
<section>
    <ul>
	    <li></li>
    	<li></li>
    </ul>
</section>
</>

Key ์†์„ฑ ์‚ฌ์šฉํ•˜๊ธฐ

React์—์„œ๋Š” ๋ฐฐ์—ด๋กœ ๋ Œ๋”๋งํ•  ๋•Œ Key ์†์„ฑ์ด ํ•„์ˆ˜์ ์ด๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Fragment๋ฅผ ๋ฐฐ์—ด๋กœ ๋ Œ๋”๋งํ•  ๋•Œ๋„ Key ์†์„ฑ์„ ์ง€์ •ํ•ด์•ผํ•œ๋‹ค.

๋‹จ์ถ•๋ฌธ๋ฒ•์ธ <></>๋Š” Key ์†์„ฑ์„ ์ง€์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— React.Fragment๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค

// โŒ ๋‹จ์ถ• ๋ฌธ๋ฒ•์— Key ์‚ฌ์šฉ ๋ถˆ๊ฐ€
{items.map((item)=>(
	<key={item.id}>
        <span>{item.name}</span>
        <p>{item.price}</p>
    <>
))}
//โœ… Fragment๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Key ์†์„ฑ ์‚ฌ์šฉ
{items.map((item)=>(
	<React.Fragment key={item.id}>
        <span>{item.name}</span>
        <p>{item.price}</p>
    </React.Fragment>
))}

Key ์†์„ฑ์„ ์‚ฌ์šฉํ•ด props ๋ณ€๊ฒฝ ์‹œ state ์ดˆ๊ธฐํ™”

props๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด state๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž id๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด Input ๊ฐ’์„ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ useEffect๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค key๊ฐ’์„ ์ง€์ •ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค

<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

Element

  • React ์•ฑ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„

  • virtual DOM ๋…ธ๋“œ์˜ ๊ฐ์ฒด ํ‘œํ˜„

  • ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค.

  • ํ•œ ๋ฒˆ ์ƒ์„ฑ๋˜๋ฉด ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถˆ๋ณ€ ๊ฐ์ฒด์ด๋‹ค.

Element ๋ Œ๋”๋ง

  • ๋ฃจํŠธ DOM ๋…ธ๋“œ๋Š” ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•˜๋‚˜์ง€๋งŒ, ๊ธฐ์กด ์•ฑ์— ํ†ตํ•ฉํ•  ๋•Œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ๋ฃจํŠธ DOM ๋…ธ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.

  • ๋ฆฌ์•กํŠธ DOM์ด ๋ฃจํŠธ DOM ๋…ธ๋“œ ์•„๋ž˜์˜ ๋ชจ๋“  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

<div id="root"></div>
  • ๋”ฐ๋ผ์„œ ๋ฆฌ์•กํŠธ DOM์—๊ฒŒ ๋ฃจํŠธ DOM ๋…ธ๋“œ์™€ ๋ Œ๋”๋งํ•  ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ๋ Œ๋”๋ง์„ ์ง€์‹œํ•œ๋‹ค.

const root = ReactDOM.createRoot(
  document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);

์ƒํƒœ๊ฐ€ ์—†๋‹ค

  • ์—˜๋ฆฌ๋จผํŠธ๋Š” ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ํฌํ•จํ•ด ๋ฉ”์„œ๋“œ, ์ƒํƒœ๋ฅผ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค.

๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„๋งŒ ์—…๋ฐ์ดํŠธ

  • ๋ฆฌ์•กํŠธ DOM์€ ํ˜„์žฌ ์ƒํƒœ์™€ ๋ณ€๊ฒฝ๋  ์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

Component

Component ์ •์˜

  • props๋ฅผ ์ž…๋ ฅ์œผ๋กœ ๋ฐ›์•„ React ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

  • React์—์„œ๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์™€ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ๋‹ค

  • ์ด๋ฆ„์€ ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ํ•œ๋‹ค.

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ

function Component(props) {
	return <h1> Component </h1>;
}

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ - ES6 Arrow function ๋ฌธ๋ฒ•

const Component = (props) => {
	return <h1> Component </h1>;
}

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ - ES6 Class ๋ฌธ๋ฒ•

class Component extends React.Component {
	render() {
		return <h1> Component </h1>;
	}
}

rendering

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋ฉด ๋ชจ๋“  ํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง

props

  • ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ „๋‹ฌ๋ฐ›๋Š” ๊ฐ’

  • props๋Š” Read Only ๊ฐ’์œผ๋กœ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ž„์˜๋กœ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

  • ๋”ฐ๋ผ์„œ ์ˆœ์ˆ˜ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด props๋ฅผ ๋‹ค๋ฃฌ๋‹ค.

  • ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” {props.์†์„ฑ๋ช…}

  • ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” {this.props.์†์„ฑ๋ช…}

  • props๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ๋•Œ ๊ตฌ์กฐ ๋ถ„ํ•ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์„ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

const Button = (props) => {
	return <button type={props.type}>{props.children}</button>
} 

props๋ฅผ ์ „๋‹ฌ ๋ฐ›์„ ๋•Œ ๊ตฌ์กฐ ๋ถ„ํ•ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†์„ฑ์„ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

// ๊ตฌ์กฐ๋ถ„ํ•ด๋ฅผ ์‚ฌ์šฉํ•œ props ๊ฐ€์ ธ์˜ค๊ธฐ
const Button = ({ type, children }) => {
	return <button type={type}>{children}</button>
} 

props ๊ธฐ๋ณธ๊ฐ’ ์ง€์ •ํ•˜๊ธฐ

const Button = ({ type='submit', children, placeholder='enter...' }) => {
	return <button type={type} placeholder={placeholder}>{children}</button>
} 

๋ชจ๋“  props๋ฅผ ์—˜๋ฆฌ๋จผํŠธ์— ์ „๋‹ฌํ•˜๊ธฐ

  • ์Šคํ”„๋ ˆ๋“œ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  props, ๋˜๋Š” ๋‚˜๋จธ์ง€ props๋ฅผ ์—˜๋ฆฌ๋จผํŠธ์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

const Image = (props) => {
	return <img {...props} />
}
const Image = ({a, b, ...props}) => {
    // a์™€ b๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋กœ์ง
	return <img {...props} />
}

children ์†์„ฑ

  • ์ž์‹  ์ปดํฌ๋„ŒํŠธ์˜ ํƒœ๊ทธ ์‚ฌ์ด๋กœ ๋“ค์–ด์˜ค๋Š” content ๊ฐ’์œผ๋กœ

  • props.children์œผ๋กœ ์‚ฌ์šฉ

const TitleContainer ({ chlidren }) => {
	return(
        <div className="TitleContainer">
            {children}
        </div>
        );
}
<TitleContainer>
<h1>Title: React</h1>
</TitleContainer>
// ๋ Œ๋”๋ง ๊ฒฐ๊ณผ 
<div className="TitleContainer">
	<h1>Title: React</h1>
</div>
  • ์ž์‹ ์˜ content๋กœ ์–ด๋–ค ์ž์‹ ์—˜๋ฆฌ๋จผํŠธ๊ฐ€ ์˜ฌ ์ง€ ์˜ˆ์ธกํ•˜๊ธฐ ์–ด๋ ค์šธ ๋•Œ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅ์œผ๋กœ ์ „๋‹ฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ ๊ตฌ์ฒดํ™”(ํŠน์ˆ˜ํ™”)

  • ๊ตฌ์ฒด์ ์ธ์ปดํฌ๋„ŒํŠธ => ์ผ๋ฐ˜์ ์ธ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง

  • ๊ตฌ์ฒด์ ์ธ ์ปดํฌ๋„ŒํŠธ(WelcomeDialog)์—์„œprops๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์ผ๋ฐ˜์ ์ธ ์ปดํฌ๋„ŒํŠธ(Dialog) ๊ตฌ์ฒดํ™”

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />
  );
}

Pure Component

  • ์ˆœ์ˆ˜ ํ•จ์ˆ˜์™€ ๊ฐ™์ด ๋™์ผํ•œ ์ž…๋ ฅ์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ถœ๋ ฅ์„ ๋ Œ๋”๋งํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ

  • ๋‹ค๋ฅธ ๊ฐ์ฒด๋‚˜ ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.

  • React์—์„œ๋Š” ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ˆœ์ˆ˜ ํ•จ์ˆ˜์ผ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ณ  ๋™์ž‘ํ•œ๋‹ค

์ˆœ์ˆ˜ํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•

  1. props๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ™์€ ์ž…๋ ฅ์— ๋Œ€ํ•ด ๋˜‘๊ฐ™์€ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ

  2. state๋ฅผ ์ตœ์†Œํ•œ์œผ๋กœ ์œ ์ง€

  3. unit test๋ฅผ ์ž‘์„ฑ

import / export

์–ด๋Š ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋“  ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

export default () => {}์™€ ๊ฐ™์€ ๋ฐฉ์‹์€ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐฉ์‹

๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐฉ์‹์€ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์›ํ•˜๋Š” ์ด๋ฆ„์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.

export default function App() {
    ...
}
const App = () => {
    ...
}
export default App;
import App from './App.js';
import AppContainer from './App.js';

๋ช…๋ช…๋œ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐฉ์‹

๋ช…๋ช…๋œ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฐฉ์‹์€ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์–‘์ชฝ์˜ ์ด๋ฆ„์ด ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ€์ ธ์˜จ ํ›„์—๋Š” ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜์žˆ๋‹ค.

export function App() {
...
}
export const App = () => {
...
}
import { App } from './App.js'
import { App as AppContainer } from './App.js'

Virtual DOM

The virtual DOM (VDOM) is a programming concept where an ideal, or โ€œvirtualโ€, representation of a UI is kept in memory and synced with the โ€œrealโ€ DOM by a library such as ReactDOM. This process is called reconciliation. -react docs

๊ฐ€์ƒ UI๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์ด๋ฅผ ์‹ค์ œ DOM์— ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ์‹

๋ Œ๋” ๋‹จ๊ณ„: ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ณ„์‚ฐ

์ปค๋ฐ‹ ๋‹จ๊ณ„: ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ DOM์— ์ ์šฉ

๊ฐ€์ƒDOM์ด๋ผ๋Š” ๋‹จ์–ด๋ฅผ ์ ์  ์•ˆ์“ฐ๋Š” ์ถ”์„ธ์ด๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•ญ์ƒ DOM์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค.

State

State๋ž€

์ƒํƒœ: React์—์„œ๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ™”๋ฉด์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ์–ตํ•ด์•ผ ํ•  ๊ฐ’๋“ค์„ ์ƒํƒœ๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

๋‹จ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„: ์ƒํƒœ๋Š” props๋ฅผ ํ†ตํ•ด ๋‹จ๋ฐฉํ–ฅ์œผ๋กœ ์ƒ์œ„ ์š”์†Œ์—์„œ ํ•˜์œ„ ์š”์†Œ๋กœ ํ๋ฆ…๋‹ˆ๋‹ค.

์—ญ๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ํ๋ฆ„: ํ•˜์œ„ ์š”์†Œ์—์„œ ์ƒ์œ„ ์š”์†Œ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ƒ์œ„ ์š”์†Œ์—์„œ setter ํ•จ์ˆ˜๋ฅผ props๋กœ ์ „๋‹ฌ

๋ถˆ๋ณ€์„ฑ: React์˜ ๋ชจ๋“  ์ƒํƒœ๋ฅผ ๋ถˆ๋ณ€ํ•ด์•ผ ํ•œ๋‹ค. (์ด์ „ ์ƒํƒœ์™€ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ตœ์ ํ™”)

ํ•„์š”ํ•œ ์ด์œ 

  1. ์ง€์—ญ ๋ณ€์ˆ˜๋Š” ๋ Œ๋”๋ง ๊ฐ„์— ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋˜์ง€ ์•Š๋Š”๋‹ค.

    1. ๋ Œ๋”๋ง ๋  ๋•Œ๋งˆ๋‹ค ๋ณ€์ˆ˜ ๊ฐ’์ด ์ดˆ๊ธฐํ™”

  2. ๋ณ€์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.

    1. ๋ณ€์ˆ˜์˜ ๊ฐ’๊ณผ ๋ Œ๋”๋ง๋˜์–ด ๋ณด์—ฌ์ง€๋Š” ๊ฐ’์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

State ๊ณ ๋ฅด๊ธฐ

  • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ๋ณ€ํ•จ์—†์ด ์œ ์ง€ ๋˜๋Š” ๊ฐ’ -> ์ƒํƒœ๊ฐ€ ์•„๋‹˜(์ƒ์ˆ˜)

  • ๋ถ€๋ชจ ์š”์†Œ๋กœ ๋ถ€ํ„ฐ ๋‚ด๋ ค ๋ฐ›๋Š” ๊ฐ’ -> ์ƒํƒœ๊ฐ€ ์•„๋‹˜(props)

  • ์กด์žฌํ•˜๋Š” ์ƒํƒœ์™€ props๋ฅผ ์‚ฌ์šฉํ•ด ๊ณ„์‚ฐ๋˜์–ด์งˆ ์ˆ˜ ์žˆ๋Š” ๊ฐ’ -> ์ƒํƒœ๊ฐ€ ์•„๋‹˜(useMemo๋ฅผ ์‚ฌ์šฉ)

State ์œ„์น˜ ์ •ํ•˜๊ธฐ

  1. ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ

  2. ์ฐพ์€ ์š”์†Œ๋“ค์˜ ๊ณตํ†ต ์กฐ์ƒ ์š”์†Œ๋ฅผ ์ฐพ๊ธฐ

  3. State ์œ„์น˜ ์ •ํ•˜๊ธฐ. ์ ์ ˆํ•œ ์œ„์น˜๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด ์ƒˆ๋กœ์šด ๊ณตํ†ต ์š”์†Œ๋ฅผ ๋งŒ๋“ค์–ด ์ƒ์œ„์— ์œ„์น˜์‹œํ‚ค๊ธฐ

๋ฐฐ์—ด์„ ์ƒํƒœ๋กœ ์‚ฌ์šฉ

  • ๋ฐฐ์—ด์„ ์ƒํƒœ๋กœ ์‚ฌ์šฉํ•  ๋•Œ์—๋„ ์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ ๋ฐฐ์—ด ์š”์†Œ์— ๊ฐ’์„ ์ง์ ‘ ํ• ๋‹นํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

  • concat, filter, slice, map ๋“ฑ์˜ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

ํผ

์ œ์–ด ์ปดํฌ๋„ŒํŠธ

  • HTML์—์„œ์˜ ํผ์€ ์—˜๋ฆฌ๋จผํŠธ ์ž์ฒด๊ฐ€ ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค

  • React์—์„œ๋Š” State๋ฅผ ์‚ฌ์šฉํ•ด **์‹ ๋ขฐ ๊ฐ€๋Šฅํ•œ ๋‹จ์ผ ์ถœ์ฒ˜**๋ฅผ ํ†ตํ•ด ์ œ์–ด๋œ๋‹ค.

๊ธฐ๋ณธ์ ์ธ Input ์‚ฌ์šฉ๋ฒ•

<input type="text" value={value} onChange={handleChange} />
<textarea value={this.state.value} onChange={this.handleChange} />
<select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
</select>
<select multiple={true} value={['grapefruit', 'lime']}>

file Input

  • ์ฝ๊ธฐ ์ „์šฉ ๊ฐ’์œผ๋กœ React์—์„œ ๋น„์ œ์–ด ์ปดํฌ๋„ŒํŠธ

ํ•ธ๋“ค๋ง ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉ

  • input์˜ name ์†์„ฑ๊ณผ State์˜ ํ‚ค๊ฐ’์„ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ

handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

Input Null๊ฐ’ ์กฐ์‹ฌํ•˜๊ธฐ

  • input์˜ value prop์œผ๋กœ null์ด๋‚˜ undefined๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.

 const [value, setValue] = useState("");
    const handleSubmit = () => {
      alert(value)
    }
      return (
        <form onSubmit={handleSubmit}>
          <label>
            Name:
            <input type="text" value={value} onChange={(e) => 						         setValue(e.target.value)} />
          </label>
          <input type="submit" value="Submit" />
        </form>
      );

ํผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

https://formik.org/

์™ธ๋ถ€ ๋ฐ์ดํ„ฐ

HTTP ์š”์ฒญ๊ณผ Promise์—๋Š” 3๊ฐ€์ง€ ์ƒํƒœ ์ง„ํ–‰์ค‘, ์„ฑ๊ณต,์‹คํŒจ๊ฐ€ ์žˆ๋‹ค.

๋ฐ˜๋“œ์‹œ 3๊ฐ€์ง€ ์ƒํƒœ์— ๋Œ€ํ•ด ๋ชจ๋‘ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

fetch() ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

  • useEffect() -> fetch()

  • useState() ->

import React, { useState, useEffect } from "react";
const GitHubUser = ({ username }) => {
  const [data, setData] = useState();

  useEffect(() => {
    if (!login) return;
    fetch(`https://api.github.com/users/${login}`)
      .then((res) => res.json())
      .then(setData)
      .catch(console.error);
  }, [login]);
  if (data) return <pre>{JSON.stringify(data, null, 2)}</pre>;
  return null;
};

export default GitHubUser;

๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

  • key๊ฐ’์„ ์‚ฌ์šฉํ•ด ๋ฌธ์ž์—ด ํ˜•ํƒœ๋กœ ์ €์žฅ

  • ๊ฐ์ฒด ์ €์žฅ => JSON ๋ฌธ์ž์—ด๋กœ ์ €์žฅ

  • ๊ฐ์ฒด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ => JSON ๋ฌธ์ž์—ด ํŒŒ์‹ฑ

๋ชจ๋‘ ๋™๊ธฐ์ ์ธ ์ž‘์—…์ด๋ฏ€๋กœ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.

const loadJSON = key =>
	key && JSON.parse(localStorage.getItem(key));
const saveJSON = (key, data) => 
	localStorage.setItem(key, JSON.stringify(data));
const [data, setData] = useState(loadJSON(`user: ${login}`));
useEffect(() => {
	if(!data) return;
	if (data.login === login) return;
	const {name, avatar_url, location} = data;
	saveJSON(`user: ${login}`, {
		name, 
		login,
		avatar_url,
		location,
	});
}, [data]);

Context

  • ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณต

  • ์ „์—ญ์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•

  • ex. ํ˜„์žฌ ๋กœ๊ทธ์ธ ์œ ์ €, ํ…Œ๋งˆ, ์„ ํ˜ธํ•˜๋Š” ์–ธ์–ด ๋“ฑ

  • ์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” ๊ณณ์€ ์ตœํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์ธ๋ฐ props๋กœ ๊ณ„์† ๋‚ด๋ ค ๋ฐ›๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ

  • const MyContext = React.createContext(defaultValue);

Context.Provider

  • ๋ฆฌ์•กํŠธ context์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š” ๊ณณ

  • context๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ context์˜ ๋ณ€ํ™”๋ฅผ ์•Œ๋ฆผ

<MyContext.Provider value={/* ์–ด๋–ค ๊ฐ’ */}>

Context.Consumer

  • ๋ฆฌ์•กํŠธ context๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ณณ

  • context ๋ณ€ํ™”๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ.

  • ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ ์ค‘ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด Provider์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ „๋‹ฌํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉ

  • Context.Consumer์˜ ์ž์‹์€ ํ•จ์ˆ˜๋กœ์„œ context์˜ ํ˜„์žฌ๊ฐ’์„ ๋ฐ›์•„ -> React ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜

<MyContext.Consumer>
  {value => /* context ๊ฐ’์„ ์ด์šฉํ•œ ๋ Œ๋”๋ง */}
</MyContext.Consumer>

Render Props

  • ๋ Œ๋”๋ง๋˜๋Š” ํ”„๋กœํผํ‹ฐ

  • ๋ฌด์—‡์„ ๋ Œ๋”๋งํ• ์ง€ ์•Œ๋ ค์ฃผ๋Š” ํ•จ์ˆ˜

  • ์ปดํฌ๋„ŒํŠธ ์žฌ์‚ฌ์šฉ์„ฑ์„ ์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค.

<List 
    data ={data}
    renderItem={item => (<li>item.name</li>)} 
/>

const List ({ render,data }) => {
    return (
        <ul>
            {data.map((item,idx) => renderItem(item))}
        </ul>)
}

https://ko.reactjs.org/docs/render-props.html

๋ชฉ๋ก ๊ฐ€์ƒํ™”

https://ko.reactjs.org/docs/optimizing-performance.html#virtualize-long-lists

์Šคํƒ€์ผ๋ง

ํด๋ž˜์Šค

ํด๋ž˜์Šค ๋™์ ์œผ๋กœ ํ• ๋‹นํ•˜๊ธฐ

<div className={`body` ${isOpen ? 'open' : ''}}></div>

Event

  • ์ด๋ฒคํŠธ ํ•จ์ˆ˜ ์ด๋ฆ„์€ ๊ด€๋ก€์ ์œผ๋กœ handle๋กœ ์‹œ์ž‘ํ•˜๊ณ  ๋’ค์—๋Š” ๋Œ€๋ฌธ์ž๋ฅผ ์‚ฌ์šฉ(ex. handleClick)

  • ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹Œ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ์ „๋‹ฌ

export default function Button() {
  function handleClick() {
    alert('You clicked me!');
  }

  return (
    <button onClick={handleClick}>
      Click me
    </button>
  );
}

props๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ „๋‹ฌ

  • props๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ „๋‹ฌํ•  ๋•Œ๋Š” on์œผ๋กœ ์‹œ์ž‘ํ•˜๊ณ  ๋’ค์—๋Š” ๋Œ€๋ฌธ์ž๋ฅผ ์‚ฌ์šฉ(ex. onClick)

export default function Button({ onClick }) {

  return (
    <button onClick={onClick}>
      Click me
    </button>
  );
}

์ด๋ฒคํŠธ ์ „ํŒŒ ์ค‘์ง€

const handleClick = (e) => {
	e.stopPropagation();
}

๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์ง€

const handleSubmit = (e) => {
	e.preventDefault();
}

Last updated