JiwonDev

React #5 create-react-app

by JiwonDev

react ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ด๋ด…์‹œ๋‹ค.

์ฝ˜์†”์ฐฝ์— npx create-react-app ์„ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜ ํŽธ์ง‘๊ธฐ์˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

create-react-app.dev/docs/getting-started

 

Getting Started | Create React App

Create React App is an officially supported way to create single-page React

create-react-app.dev

์ฐธ๊ณ ๋กœ ์ด ๋ฐฉ์‹์œผ๋กœ ์„ค์น˜ํ•˜๊ฒŒ ๋˜๋ฉด yarn ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ €๊ฐ€ ํ•จ๊ป˜ ์„ค์น˜๋ฉ๋‹ˆ๋‹ค.

yarn์€ ํŽ˜์ด์Šค๋ถ์—์„œ npm์ฒ˜๋Ÿผ ์‚ฌ์šฉํ• ๋ ค๊ณ  ๋งŒ๋“  ์˜์กด์„ฑ ๊ด€๋ฆฌ ํ”„๋กœ์ ํŠธ ๋งค๋‹ˆ์ €์ธ๋ฐ

npm์˜ ๋‹จ์ ์ธ ํŒจํ‚ค์ง€ ์„ค์น˜ ์†๋„์™€ ๋ณด์•ˆ์„ฑ์„ ๊ฐœ์„ ํ• ๋ ค๊ณ  ๋งŒ๋“  ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

๋‘˜ ์ค‘ ๋ญ๊ฐ€ ๋” ์ข‹๋‹ค๊ธฐ๋ณด๋‹ค๋Š” ๋‘˜ ๋‹ค ์žฅ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

์‚ฌ์šฉ๋ฒ•์€ npm๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.

npm install -g yarn
yarn start

 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑ ์™„๋ฃŒํ–ˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํ•˜๊ฒŒ ์ถ”๊ฐ€๋œ ํŒŒ์ผ์„ ์„ค๋ช…ํ•˜์ž๋ฉด

manifest.json : ์•ฑ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ •๋ณด๋ฅผ ๋‹ด์€ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ๋ฐฐ๊ฒฝ์ƒ‰, ์•ฑ์˜ ์ด๋ฆ„, ํ™ˆ์Šคํฌ๋ฆฐ ์•„์ด์ฝ˜๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

index.js : ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์˜ ์ง„์ž…์ ์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— render ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

App.css, Index.css : cssํŒŒ์ผ์ด ํ•จ๊ป˜ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

ํ”„๋กœ์ ํŠธ์ด๋ฆ„.iml : node.js์˜ ์„ค์ •ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

yarn.lock : yarn์˜ ์„ค์ •ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

reportWebVitals.js : ๋ฆฌ์•กํŠธ๋ž‘ ๊ด€๋ จ์€ ์—†๊ณ , ์›น ํŽ˜์ด์ง€์˜ ์ƒํƒœ์™€ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์ด์ „ ๋ฆฌ์•กํŠธ๋ฒ„์ „์—์„œ๋Š” serviceWorker.js ๋ผ๊ณ  ๋ถˆ๋ ธ์Šต๋‹ˆ๋‹ค.

 setupTests.js : ๋ฆฌ์•กํŠธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์šฉ. ๋‚˜์ค‘์— ํ”„๋กœ์ ํŠธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋ฐฐ์šฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

#1 ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ

ํ”„๋กœ์ ํŠธ src ํด๋”์•ˆ์— components ํด๋”๋ฅผ ๋งŒ๋“ค๊ณ  ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค.

์ฐธ๊ณ ๋กœ hot-loader ํ”Œ๋Ÿฌ๊ทธ์ธ๋„ ํ•จ๊ป˜ ์„ค์น˜๋˜์—ˆ๋‹ค๋ฉด ํ”„๋กœ์ ํŠธ๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ์ˆ˜์ •๋ณธ์ด ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

// index.js , ๊ธฐ๋ณธ ์ƒ์„ฑ๋œ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์˜ ์‹œ์ž‘์ง€์ 

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './Components/App';
import reportWebVitals from './reportWebVitals';

// React.StrictMdoe ๊ฐ์ฒด๋Š” ์•ฑ ๋‚ด์˜ ์ž ์žฌ์ ์ธ ๋ฌธ์ œ๋ฅผ ์žก๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.
// ์ปดํฌ๋„ŒํŠธ์˜ ์ƒ๋ช…์ฃผ๊ธฐ, ์•ˆ์ •์„ฑ, ๊ถŒ์žฅ๋˜์ง€์•Š๋Š” ์‚ฌ์šฉ๋ฒ•๋“ฑ์„ ์ ๊ฒ€ํ•˜๋Š” ๋„๊ตฌ์ด๋ฉฐ 
// ์‚ญ์ œํ•˜์…”๋„ ์ƒ๊ด€์€ ์—†์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  index.js ๋ง๊ณ  ๋‹ค๋ฅธ ๊ณณ์—๋„ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๊ตฌ์š”.
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);Q


// ๋กœ๊ทธ๋ฅผ ๋‚จ๊ธฐ๋Š” ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ํ•„์š”์—†๋‹ค๋ฉด ์ง€์›Œ๋„ ๋ฉ๋‹ˆ๋‹ค.
// Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

// src/Components/App.js

import React from "react";
import Contact from "./Contact";

export default class App extends React.Component{
    render() {
        return(
            <div>
                <h1> Hello </h1>
                <Contact/>
            </div>
        )
    }
}

// src/Components/ContactInfo.js

import React from "react";

// export default๋ฌธ์„ ์ด๋ ‡๊ฒŒ ํด๋ž˜์Šค ์„ ์–ธ ์•ž์— ์ž‘์„ฑํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.
export default class ContactInfo extends React.Component{
    render() {
        return(
            <div>
                {this.props.contact.name}
                {this.props.contact.phone}
            </div>
        )
    }
}
import React from "react";
import ContactInfo from "./ContactInfo";

export default class Contact extends React.Component {
    constructor(props) {
        super(props);
        this.state={
            // ๋ฐ์ดํ„ฐ๋ฅผ [๊ฐ์ฒด, ๊ฐ์ฒด...] ํ˜•ํƒœ๋กœ state์— ๋“ฑ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค.
            contactData:[
                {name:'Jiwo1',phone:'010-9999-9991'},
                {name:'Jiwo2',phone:'010-9999-9992'},
                {name:'Jiwo3',phone:'010-9999-9993'},
                {name:'Jiwo4',phone:'010-9999-9994'},
            ]
        }
    }

    render() {
        // const mapToComponent = (contactData) => {
        //     return contactData.map((contac,index) => {
        //         return (<ContactInfo contact={contac} key={index}/>)
        //     })
        // };
        const mapToComponent = (data) =>
            data.map( (contact, i) =>
                <ContactInfo contact={contact} key={i}/>
                )

        return (
            <div>
                {/* ์œ„์—์„œ ๋งŒ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ.*/}
                {mapToComponent(this.state.contactData)}
            </div>
        )
    }
}

 

#2. Contact ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ •

ํ•ด๋‹น ์ฝ”๋“œ์—์„œ๋Š” *๋”๋ณด๊ธฐ JS ์˜ Sort์™€ Filter๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋”๋ณด๊ธฐ

arr.sort( [compareFunction] )
ํ•ด๋‹น ๋ฐฐ์—ด์„ ์œ ๋‹ˆ์ฝ”๋“œ ๊ธฐ์ค€ ์˜ค๋ฆ„์ฐจ์ˆœ (๋˜๋Š” ์ฃผ์–ด์ง„ ๋น„๊ตํ•จ์ˆ˜)๋กœ ์ •๋ ฌํ•ฉ๋‹ˆ๋‹ค.
์ž…๋ ฅํ•œ ๋ฐฐ์—ด ์ˆœ์„œ ์ž์ฒด๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

var name = [ 'la', 'ql' , 'qkw' ]

name.sort()

var name = [ 'la', 'ql' , 'qkw' ]
name.sort()

 

arr.filter( callback )

arr.filter( (์š”์†Œ, ์ธ๋ฑ์Šค, ๋ฐฐ์—ด) )

ํ•ด๋‹น ๋ฐฐ์—ด์—์„œ callback ํ•จ์ˆ˜๋ฅผ ์ ์šฉ ํ–ˆ์„ ๋•Œ true๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์š”์†Œ๋งŒ ๋‚จ๊ฒจ ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๊ธฐ์กด์˜ ๋ฐฐ์—ด์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// ์ •์ˆ˜ ๋ฐฐ์—ด์—์„œ 5์˜ ๋ฐฐ์ˆ˜์ธ ์ •์ˆ˜๋งŒ ๋ชจ์œผ๊ธฐ
var arr = [4, 15, 377, 395, 400, 1024, 3000];
var arr2 = arr.filter(function (n) {
    return n % 5 == 0;
});
console.log(arr2); // [15, 395, 400, 3000]

Contact ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์ •ํ•ด์„œ ๊ฒ€์ƒ‰์ฐฝ๊ณผ ๊ทธ ๊ฒ€์ƒ‰์ฐฝ์˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•  ๋กœ์ปฌ state๋ฅผ ๋งŒ๋“ค์–ด ์ค์‹œ๋‹ค.

์‹คํ–‰ํ™”๋ฉด

import React from "react";
import ContactInfo from "./ContactInfo";

export default class Contact extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            keyword: '', // ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ๋ฅผ ์ €์žฅํ•  state๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
            // ๋ฐ์ดํ„ฐ๋ฅผ [๊ฐ์ฒด, ๊ฐ์ฒด...] ํ˜•ํƒœ๋กœ state์— ๋“ฑ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค.
            contactData: [
                {name: 'Jiwo1', phone: '010-9999-9991'},
                {name: 'Jiwo2', phone: '010-9999-9992'},
                {name: 'Jiwo3', phone: '010-9999-9993'},
                {name: 'Jiwo4', phone: '010-9999-9994'},
            ]
        }
        // ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋‚ด์—์„œ this ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ”์ธ๋“œ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
        this.handleChange = this.handleChange.bind(this);
    }

// ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž…๋ ฅ๊ฐ’์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ state์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
    handleChange(e) {
        this.setState({
            keyword: e.target.value
        })
    }

    render() {
        const mapToComponent = (data) =>
            data.map((contact, i) =>
                <ContactInfo contact={contact} key={i}/>
            )

        return (
            <div>
                <h1>Contacts</h1>
                <input type="text" name="keyword" placeholder="Search"
                       value={this.state.keyword} onChange={this.handleChange}/>

                {/* ์œ„์—์„œ ๋งŒ๋“  ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ.*/}
                {mapToComponent(this.state.contactData)}
            </div>
        )
    }
}

๊ทธ๋ฆฌ๊ณ  mapToComponent ๋ฉ”์„œ๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ ์ด๋ฆ„ ๊ฒ€์ƒ‰๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค.

const mapToComponent = (data) =>
            data.filter((contact)=>contact.name.toLowerCase().includes(this.state.keyword.toLowerCase()))
                .map((contact, i) => <ContactInfo contact={contact} key={i}/>
            )

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ