JavaScript 기초

React 코드에 자주 나오는 JavaScript만

핵심 포인트

  • React에서 막히는 곳은 대부분 React가 아니라 JavaScript입니다. 배열 함수, 비교 기호, 문법의 세 가지로 나누어 정리했습니다
  • map, filter, ...(스프레드)는 원래 배열을 바꾸지 않고 "새 배열"을 만듭니다. 그래서 React의 state와 잘 맞습니다
  • 모르는 문법은 아래 표에서 한 문장짜리 "규칙"을 읽은 뒤 데모에서 직접 해 보세요

한눈에 보기

배열 함수

문법규칙(한 문장)예시
.map((x) => …)하나씩 꺼내서 모양을 바꾼 새 배열을 만든다members.map((m) => <li>{m.name}</li>)
.filter((x) => 조건)조건에 맞는 것만 남긴 새 배열을 만든다members.filter((m) => m.plan === "유료")
.find((x) => 조건)조건에 맞는 첫 번째 하나를 돌려준다members.find((m) => m.id === 2)
.sort((a, b) => 숫자)두 개씩 비교해서 정렬한다. 결과가 음수면 a가 앞[...items].sort((a, b) => a.price - b.price)
.slice(시작, 끝)시작부터 끝 바로 앞까지 잘라 낸다 (0부터 센다)items.slice(0, 6)
.reduce((합계, x) => …, 0)하나씩 보면서 하나의 값(합계 등)으로 모은다items.reduce((sum, i) => sum + i.price, 0)
.includes(x)x가 들어 있는지 (true / false)name.includes(query)
.length배열이면 개수, 문자열이면 글자 수{members.length}명
.some((x) => 조건)하나라도 조건에 맞는 것이 있는지 (true / false)items.some((i) => i.stock === 0)
.join(구분자)배열을 구분자로 이어 붙인 하나의 문자열로 만든다tags.join(", ")

비교하기·잇기

문법규칙(한 문장)예시
===왼쪽과 오른쪽이 같은지plan === "유료"
!==왼쪽과 오른쪽이 같지 않은지m.id !== id
> >= < <=초과·이상·미만·이하quantity >= stock
!반대로 바꾼다 (true ↔ false)!isOpen
&&그리고. JSX에서는 "맞으면 보여 준다"{error && <p>{error}</p>}
||또는!isDirty || isSubmitting
조건 ? A : B맞으면 A, 아니면 B{open ? "닫기" : "열기"}
a ?? ba가 비어 있으면(null·undefined) b를 쓴다user.name ?? "게스트"
a?.ba가 비어 있어도 오류를 내지 않고 undefined가 된다user?.name

문법

문법규칙(한 문장)예시
(x) => …함수를 만든다 (x를 받아서 …한다)() => setCount(count + 1)
(x) => { … }안에 여러 줄을 쓸 수 있는 함수onClick={() => { reset(); setSent(false) }}
const와 letconst는 다시 넣지 않고, let은 나중에 다시 넣는다let sorted = filtered
const [a, setA] = …돌아온 두 값에 이름을 붙여서 꺼낸다const [count, setCount] = useState(0)
const { a, b } = …상자({ }) 안에서 쓸 것만 이름으로 꺼낸다const { user } = useAuth()
function X({ a })컴포넌트에 전달된 것(props)을 이름으로 받는다function Card({ title }) { … }
`…${x}…`문자열 안에 값을 넣는다 (템플릿 리터럴)`${count}건`
[...x, 추가]배열을 복사하고 마지막에 추가한 새 배열setMembers([...members, newMember])
{ ...x, 키: 값 }객체 하나를 복사하고 한 곳만 바꾼 새 객체{ ...member, id: 7 }
import / export다른 파일의 컴포넌트를 쓴다 / 다른 파일에서 쓸 수 있게 내보낸다import { Button } from "./button"
async / await시간이 걸리는 일(데이터 가져오기 등)이 끝나기를 기다린다const res = await fetch(url)

직접 해 보기

import { useState } from "react"

// 회원 목록 (처음 3명)
const initialMembers = [
  { id: 1, name: "김민준", plan: "유료" },
  { id: 2, name: "이서연", plan: "무료" },
  { id: 3, name: "박지훈", plan: "유료" },
]

export default function App() {
  // 회원 목록 ("1명 추가"로 늘어남)
  const [members, setMembers] = useState(initialMembers)
  // "유료만 보기"가 눌려 있는지 (true = 눌려 있음)
  const [paidOnly, setPaidOnly] = useState(false)

  // 화면에 보여 줄 목록: 눌려 있으면 유료 회원만, 아니면 전원
  const shown = paidOnly ? members.filter((member) => member.plan === "유료") : members

  // 1명 추가: 지금 회원을 모두 나열하고 그 마지막에 새 1명을 더한 목록으로 만든다
  function addMember() {
    const newId = members.length + 1
    setMembers([...members, { id: newId, name: "회원" + newId, plan: "무료" }])
  }

  return (
    <div style={{ padding: 16, fontFamily: "sans-serif" }}>
      <div style={{ display: "flex", gap: 8 }}>
        {/* 누를 때마다 유료만 ↔ 전원 을 전환한다 (! = 반대로 바꾸기) */}
        <button onClick={() => setPaidOnly(!paidOnly)}>{paidOnly ? "전원 보기" : "유료만 보기"}</button>
        <button onClick={() => addMember()}>1명 추가</button>
      </div>
      <p>{shown.length}명</p>
      {/* 화면에 보여 줄 목록을 한 명씩 "이름 (플랜)" 줄로 만든다 */}
      <ul>
        {shown.map((member) => (
          <li key={member.id}>
            {member.name} ({member.plan})
          </li>
        ))}
      </ul>
    </div>
  )
}
  1. "유료만 보기"를 눌러 보세요 (filter로 유료 회원만 있는 새 배열이 만들어집니다)
  2. "유료"를 "무료"로 바꿔 보세요
  3. "1명 추가"를 몇 번 눌러 보세요 ([...members, 새 사람]으로 마지막에 한 명씩 늘어납니다)

자주 하는 실수

members.push(사람)으로는 화면이 바뀌지 않음
push는 원래 배열을 고쳐 쓸 뿐이라 React가 바뀐 것을 알아차리지 못합니다. [...members, 사람]으로 새 배열을 만들어 setMembers에 넘깁니다.
.sort는 원래 배열을 고쳐 쓴다
map이나 filter와 달리 sort는 원래 배열 자체를 정렬합니다. [...items].sort(…)처럼 복사한 뒤에 정렬합니다.
=는 "넣기", ===는 "같은지"
조건 안에 =라고 쓰면 비교하지 않고 값을 넣어 버립니다. 비교할 때는 ===를 씁니다.