๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐Ÿ’ป๐Ÿ’ญ๐ŸŽง๐ŸŒ

[React Native] 02-3. ์ปดํฌ๋„ŒํŠธ์™€ ์†์„ฑ ์ดํ•ดํ•˜๊ธฐ ๋ณธ๋ฌธ

๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

[React Native] 02-3. ์ปดํฌ๋„ŒํŠธ์™€ ์†์„ฑ ์ดํ•ดํ•˜๊ธฐ

adorableco 2023. 8. 4. 04:32
๋ฐ˜์‘ํ˜•

2. ๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ๊ธฐ๋ณธ ๋‹ค์ง€๊ธฐ  ์ค‘ 02-3 ์ปดํฌ๋„ŒํŠธ์™€ ์†์„ฑ ์ดํ•ดํ•˜๊ธฐ๋ฅผ ๊ณต๋ถ€ํ•ด๋ณด๊ฒ ์๋‹ˆ๋‹ค.

(์ƒ๊ฐ๋ณด๋‹ค ํ•œ ๋ถ€๋ถ„ ์ฑ•ํ„ฐ์˜ ์–‘์ด ๋งŽ์•„์„œ ์ด๋ฒˆ ๊ธ€๋ถ€ํ„ฐ ์ œ๋ชฉ์„ ์ฑ•ํ„ฐ๊ฐ€ ์•„๋‹Œ ์„œ๋ธŒ ์ฑ•ํ„ฐ๋กœ ๋ฐ”๊พธ๊ธฐ๋กœ ๊ฒฐ์ •...)


faker ์™ธ๋ถ€ ํŒจํ‚ค์ง€ ์„ค์น˜ํ•˜๊ธฐ

 โžก๏ธ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๊ฐ€์งœ ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“œ๋Š” ํŒจํ‚ค์ง€

npm i faker
npm i -D @types/faker

โ€ป npm i faker ๋กœ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์—†์„ ๋•Œ

faker ํŒจํ‚ค์ง€ ์ œ์ž‘์ž๊ฐ€ ํŒจํ‚ค์ง€๋ฅผ ๊ณ ์˜์ ์œผ๋กœ ์†์ƒ์‹œ์ผœ ๋†“์•˜๋‹ค๊ณ  ํ•œ๋‹ค. (์ž์„ธํ•œ ์ด์•ผ๊ธฐ๋Š” ๋ชจ๋ฅด๊ฒ ์Œ)

๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋กœ ๋‹ค๋ฅธ ๋ฒ„์ „์˜ faker ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๋ฉด ๋œ๋‹ค.

npm i -D faker@5

 

 

src/data/util.ts ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑ

export const makeArray = (length: number) => new Array(length).fill(null)
export const random = (min: number, max: number): number =>
  Math.round(Math.random() * (max - min)) + min
export const unsplashUrl = (width: number, height: number): string =>
  'https://source.unsplash.com/random/${width}x${height}'
export const avatarUriByName = (name: string) =>
  'https://ui-avatars.com/api/?name=${name.split(" ").join("+")}'

โœ… unsplash.com : ํŠน์ • ํฌ๊ธฐ์˜ ์ด๋ฏธ์ง€๋ฅผ ์ œ๊ณต๋ฐ›๋Š”๋‹ค.

โœ… ui-avatars.com : ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ์•„๋ฐ”ํƒ€ ์ด๋ฏธ์ง€๋ฅผ ์ œ๊ณต๋ฐ›๋Š”๋‹ค.

 

src/data/faker.ts ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑ

โžก๏ธ faker ํŒจํ‚ค์ง€์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ๊ฐ€์ง€๋ฅผ ๋žœ๋คํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

import faker from 'faker'
import * as U from './util'
export const randomId = (): string => faker.datatype.uuid()
export const randomName = (): string => faker.name.findName()
export const randomEmail = (): string => faker.internet.email()
export const randomAvatarUrl = (name?: string): string =>
  U.avatarUriByName(name ?? randomName())
export const randomDate = (): Date => faker.date.recent()
export const randomParagraphs = (count: number = 2): string =>
  U.makeArray(count).map(faker.lorem.paragraph).join('\n')
export const randomImage = (): string =>
  U.unsplashUrl(U.random(800, 800), U.random(800, 1000))

name ?? randomName() ์˜๋ฏธ : ์—ฐ์‚ฐ์ž ์•ž์˜ ๋ณ€์ˆซ๊ฐ’(์—ฌ๊ธฐ์—์„  name)์ด null ์ด๋‚˜ undefined ๋ผ๋ฉด ์—ฐ์‚ฐ์ž ๋’ค์˜ ๊ฐ’(์—ฌ๊ธฐ์„œ๋Š” randomName()) ์„ ์‚ฌ์šฉํ•˜๋ผ๋Š” ๋œป์ด๋‹ค.

 

 

โ€ป faker ํŒจํ‚ค์ง€ ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํŒจํ‚ค์ง€๋“ค์ด ์ธ์‹์ด ์•ˆ๋˜๋ฉด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค๋ฉด

๋”๋ณด๊ธฐ

๋ชจ๋“ˆ 'faker'์— ๋Œ€ํ•œ ์„ ์–ธ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. '/Users/parkseyeon/React-Native/ch02/ch02_3/node_modules/faker/index.js'์—๋Š” ์•”์‹œ์ ์œผ๋กœ 'any' ํ˜•์‹์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  ํ•ด๋‹น ํ•ญ๋ชฉ์ด ์žˆ๋Š” ๊ฒฝ์šฐ 'npm i --save-dev @types/faker'์„(๋ฅผ) ์‹œ๋„ํ•˜๊ฑฐ๋‚˜, 'declare module 'faker';'์„(๋ฅผ) ํฌํ•จํ•˜๋Š” ์ƒˆ ์„ ์–ธ(.d.ts) ํŒŒ์ผ ์ถ”๊ฐ€

โœ… d.ts ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ declare module '๋ชจ๋“ˆ๋ช…' ์„ ์ž‘์„ฑํ•œ๋‹ค. 

 

src/data/createRandomPerson.ts ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑ

import type {IPerson} from './IPerson'
import * as F from './faker'
import * as U from './util'

export const createRandomPerson = (): IPerson => {
  const name = F.randomName()
  return {
    id= F.randomId()
    createDate: F.randomDate(),
    modifiedDate: new Date,
    name,
    email: F.randomEmail(),
    avatar: F.randomAvatarUrl(name),
    image: F.randomImage(),
    comments: F.randomParagraphs(4),
    counts: {
        comment: U.random(10,100),
        retweet: U.random(10,100),
        heart: U.random(100,1000)
    }
  }
}

 

src/data/index.ts ์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑ

// src/data ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์˜ import๋ฌธ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ž‘์„ฑ

export * from './util'
export * from './faker'
export * from './IPerson'
export * from './createRandomPerson'

 

๋งˆ์ง€๋ง‰์œผ๋กœ App.tsx ์—๋Š”

import React from 'react'
import {SafeAreaView, Text} from 'react-native'
import * as D from './src/data'

const person = D.createRandomPerson()
export default function App() {
  return (
    <SafeAreaView>
      <Text>{JSON.stringify(person, null, 2)}</Text>
    </SafeAreaView>
  )
}

โœ… JSON.stringfy() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•จ โžก๏ธ JSON.stringfy(JSON ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•  Object, replacer ํ•จ์ˆ˜, JSON ๋ฌธ์ž์—ด์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๊ณต๋ฐฑ์„ ์‚ฝ์ž…ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์นธ(๊ณต๋ฐฑ๋ฌธ์ž ๊ฐœ์ˆ˜))

 

 

์‚ฌ์šฉ์ž ์ปดํฌ๋„ŒํŠธ : User-defined component 

  • ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ(function component) ์™€ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ(class component)๊ฐ€ ์žˆ๋‹ค.

 

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

cd src
mkdir screens
touch screens/ClassComponent.tsx
cd ..

โœ… ๋ฆฌ์•กํŠธ์™€ ๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฐ˜๋“œ์‹œ Component ํด๋ž˜์Šค(react ํŒจํ‚ค์ง€์—์„œ ์ œ๊ณต)๋ฅผ ์ƒ์†ํ•ด์•ผํ•œ๋‹ค. 

 

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„

import React, {Component} from 'react'
import {Text} from 'react-native'
import * as D from '../data'

const person = D.createRandomPerson()
export default class ClassComponent extends Component {
  render() {
    return <Text>{JSON.stringify(person, null, 2)}</Text>
  }
}

โœ… ์ปดํฌ๋„ŒํŠธ ์ œ์ž‘ โžก๏ธ ์ฆ‰ ์ฝ”์–ด ํŽŒํฌ๋Š”ํ„ฐ๋ฅผ ํ™”๋ฉด์— ๋ Œ๋”๋ง ํ•˜๋Š” ์ผ

โžก๏ธ ๊ทธ๋ž˜์„œ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์—๋Š” render ๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค. 

 

 

ClassComponent.tsx

import React, {Component} from 'react'
import {Text} from 'react-native'
import * as D from '../data'

const person = D.createRandomPerson()
export default class ClassComponent extends Component {
  render() {
    return <Text>{JSON.stringify(person, null, 2)}</Text>
  }
}

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด App.tsx ๋ฅผ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

App.tsx ์—

import ClassComponent from './src/screens/ClassComponent'

๋‹ค์Œ๊ณผ ๊ฐ™์ด ClassComponent ๋ฅผ import ํ•ด์ฃผ๋ฉด 

<SafeAreaView>
      <Text>{JSON.stringify(person, null, 2)}</Text>
</SafeAreaView>


<SafeAreaView>
      <ClassComponent />
</SafeAreaView>

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๋งŒ๋“ค๊ธฐ

  • ๋ณดํ†ต ์†์„ฑ์ด ์—†๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” function ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์„ฑํ•˜๊ณ , ์†์„ฑ์ด ์žˆ๋‹ค๋ฉด ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ ๋‹ค.

ArrowComponent.tsx

import React from 'react'
import {Text} from 'react-native'
import * as D from '../data'

const person = D.createRandomPerson()
const ArrowComponent = () => {
  return <Text>{JSON.stringify(person, null, 2)}</Text>
}

export default ArrowComponent

โœ… ํด๋ž˜์Šค ๋ฐฉ์‹ ์ปดํฌ๋„ŒํŠธ์˜ render ๋ฉ”์„œ๋“œ == ํ•จ์ˆ˜ ๋ฐฉ์‹ ์ปดํฌ๋„ŒํŠธ์˜ ํ•จ์ˆ˜ ๋ชธํ†ต

 


์†์„ฑ์ด๋ž€?

  • ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜ (member variable) ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์†์„ฑ์€ ๊ทธ ๊ฐ’์ด ์ˆ˜์‹œ๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค. โžก๏ธ ๋ฆฌ์•กํŠธ์™€ ๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ๋Š” ๋ฐ”๋€ ์†์„ฑ๊ฐ’์„ ์ฆ‰๊ฐ ํ™”๋ฉด์— ๋ฐ˜์˜ํ•ด์•ผ ํ•œ๋‹ค. ( = ์žฌ๋ Œ๋”๋ง)

์†์„ฑ์˜ ์šฉ๋„ : ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์ชฝ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

 

โœ… ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ปดํŒŒ์ผ ๋•Œ๋งŒ ํ•„์š”ํ•œ ํƒ€์ž…(ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋กœ ์ปดํŒŒ์ผ ๋˜๊ณ ๋‚˜๋ฉด ์‚ฌ๋ผ์ง€๋Š” ๊ฒƒ)์€ import type ๊ตฌ๋ฌธ์œผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.

 

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๊ตฌํ˜„ํ•˜๊ธฐ

 

src/screens/Person.tsx

import React from 'react'
import type {FC} from 'react'
import * as D from '../data'
import {Text} from 'react-native'

export type PersonProps = {
  person: D.IPerson
}

const Person: FC<PersonProps> = ({person}) => {
  return <Text>{JSON.stringify(person, null, 2)}</Text>
}

export default Person // ๋‚ด๋ณด๋‚ด๊ธฐ

์—ฌ๊ธฐ์„œ ๋ฌธ๋œฉ... ๋‚ด๊ฐ€ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ ์ž˜ ๋ชจ๋ฅด๊ตฌ๋‚˜ ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

 

const ๋ณ€์ˆ˜๋ช… : (๋งค๊ฐœ๋ณ€์ˆ˜๋ช… = ์ž๋ฃŒํ˜•) => {
              ์ฒ˜๋ฆฌ๊ตฌ๋ฌธ

    }

 

๋ผ๊ณ  ํ•œ๋‹ค. ์œ„์˜ ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด๋ฉด FC<PersonProps> ๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜์ด๋ฉฐ ์ด์˜ ์ž๋ฃŒํ˜•์€ {person} ์ธ ๊ฒƒ์ด๋‹ค. 

 

 

ScrollView ์ฝ”์–ด ์ปดํฌ๋„ŒํŠธ์™€ Key ์†์„ฑ

์ฝ”์–ด ์ปดํฌ๋„ŒํŠธ (Core Component) : React Native App์˜ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋œปํ•˜๋ฉฐ ์žฌ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„

 

โœ…Person ์ปดํฌ๋„ŒํŠธ๋ฅผ ScrollView์˜ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋กœ ๋งŒ๋“ค๋ฉด ScrollView๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์Šคํฌ๋กค ๊ธฐ๋Šฅ์„ ์ด์šฉํ•ด ๋ชจ๋“  Person ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

ScrollView ๋ฅผ ์ ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

import React, {Children, Component} from 'react'
import {SafeAreaView, ScrollView, Text} from 'react-native'
import Person from './src/screens/Person'
import * as D from './src/data'

const people = D.makeArray(100).map(D.createRandomPerson)
export default function App() {
  const children = people.map(person => (
    <Person key={person.id} person={person} />
  ))
  return (
    <SafeAreaView>
      <ScrollView>{children}</ScrollView>
    </SafeAreaView>
  )
}

<Person key={person.id} person={person} /> ์—์„œ key = {person.id} ๋Š” ๋ Œ๋”๋ง ์†๋„๋ฅผ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ‚ค๊ฐ’์„ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 

โžก๏ธ person.id ๋Š” faker.datatype.uuid() ๋กœ ์ƒ์„ฑํ•œ ๊ฐ’์ด๋‹ค. (uuid : universally unique identifier)

๋ฐ˜์‘ํ˜•