November 19, 2020
npx create-react-app <νλ‘μ νΈμ΄λ¦>
λκ° μ λκ² κΉμλκ³ βνλ‘μ νΈμ΄λ¦β μΌλ‘ λμ΄ μλ λλ ν λ¦¬κ° νλ μκΈ΄λ€.
index.js κ·Έλ¦¬κ³ App.js κ° μλ€.
μΌλ¨ index.js λ root κ²½λ‘ μμΌλ‘ λ λ νκ³ μ νλ μ»΄ν¬λνΈλ₯Ό ν΅μ§Έ render ν΄ μ£Όλ ν¨μκ° μμΉνκ³ μλ€.
μκΉμλ μλμ κ°λ€.
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import Twittler from './App'
import reportWebVitals from './reportWebVitals'
ReactDOM.render(
<React.StrictMode>
<Twittler />
</React.StrictMode>,
document.getElementById('root')
)
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals()
λ΄ μ± μ΄λ¦μ βTwittlerβ λ‘ ν΄μ€ κ±°λΌμ import λΆλΆ λ° render λΆλΆμ Twittler λΌλ μ΄λ¦μΌλ‘ κ°μ μΉμλ²λ Έλ€.
μ΄μ μ¬κΈ΄ 건λ€κ² μλ€.
App.js λ‘ κ°λ©΄ λκ° μ½λκ° μκΈ°λ νλ°, μΉ λ€ μ§μλ²λ¦¬κ³
import React from 'react'
import './App.css'
export default Twittler
μλ κ² λ°κΏμ€ λ€ μμνλ©΄ λλ€.
μΈμΈν λ°μ§λΌκ³ νλλ° κ·Έλ¬λ€κ°λ νλ λλ μλ€ μΌλ¨ κ·Έλ₯ λ°μλ€μ΄κΈ°λ‘ νλ€.
μ»΄ν¬λνΈ μμ±μλ ν¨μν κ³Ό ν΄λμ€ ν λκ°μ§ μμ± λ°©λ²μ΄ μλ€.
λ³ν μ μλ μ 보 (μν) λ₯Ό κ°κ² νλ €λ©΄ λ₯ ν΄λμ€ν μ»΄ν¬λνΈλ‘ λ§λ€μ΄μΌ νλ€.
그리ꡬ μ΄λ¦μ.. Twittler λ‘ ν기루 νμΌλκΉ,
class Twittler extends React.Component {
constructor(props) {
super(props)
this.state = {
// μ΄λ€ μνλ₯Ό μ€μΌ ν μ§ μ±λ§λ€ λ€λ₯΄κ²μ§π
}
}
render() {
// κΈ°λ³Έμ UI λ₯Ό λμ°κΈ° μν ν¨μ.
}
}
μ μ΄ν΄λμ€μ λμ μλ κΈ°λ³Έ μν (Mockup-data) λ₯Ό κ°μ Έλ€ λ£μ΄ μ£Όμλ€.
λκ° μΆμΈ‘μΌλ‘λ μΆνμ μ this.state.tweets λΌλ λ°°μ΄μ μ°λ¦¬κ° μ λ ₯ν κ°μ λ°°μ΄.push λ‘ λ£μΌλ©΄ λ κ±° κ°μλ°
state λ μ§μ μμ μ΄ λΆκ°νλ€κ³ νλ€.
setState λ₯Ό μ¬μ©νλ©΄ λλ€κ³ νλλ° μΌλ¨ 그건 λμ€μΌλ‘ 미룬λ€.
class Twittler extends React.Component {
constructor(props) {
super(props)
this.state = {
tweets: [
{
uuid: 1,
writer: 'μ νμ΄π',
date: '2020-11-19',
content: '리μ‘νΈλ μ΄λ?',
},
{
uuid: 2,
writer: '건λ§μ§μπ¨π»β',
date: '2020-11-19',
content: 'Not easy for me..π',
},
],
}
}
render() {
// κΈ°λ³Έμ UI λ₯Ό λμ°κΈ° μν ν¨μ.
}
}
μΌλ¨ μλ²λ₯Ό λμ μ λ, κΈ°λ³Έμ μΈ μΈν°νμ΄μ€ μ λλ 보μ¬μ€μΌ ν ν λκΉ μ΄ λν μΌλ¨ μ μ΄ν΄λμ€μμ κ°μ Έμ λ£μ΄λ³΄μ.
// class Twittler λ΄ render ν¨μ ꡬν
render() {
<div>
<div>μμ±μ: κΉμ½λ©</div>
<div id="writing-area">
<textarea id="new-tweet-content"></textarea>
<button id="submit-new-tweet">μ κΈ μ°κΈ°</button>
</div>
<ul id="tweets">
<!-- μ΄ λΆλΆμ this.state.tweetsλ₯Ό λ°νμΌλ‘ SingleTweet μ»΄ν¬λνΈκ° λ°λ³΅ μΆλ ₯λ κ²μ
λλ€. -->
</ul>
</div>
}
μ¬νΌ λ°λ°νμ§λ§ λκ³ μ΄μ ul νκ·Έ νμμ λ£μ΄μ Έ μλ μ£Όμ λμ μ μκΉ λ£μλ λͺ©μ λ°μ΄ν°λ₯Ό λΆλ¬λ€ λ£μ΄μΌ νλ€. μ΄λ»κ² λ£μκΉ?
ul νκ·Έ νμμ κΈ λͺ©λ‘μ λΆλ¬ μμΌ νλλ° λͺ©μ λ°μ΄ν°λ νμ¬ μ΄λμ μμ§?
this.state.tweets μ μλ€. μλ μ¬μ§μ΄ λ°°μ΄μ΄λ€.
κ·Έλ¬λ©΄ μΌλ¨ JSX ννμμ μ°κΈ° μν΄ ul μλμ,
{ } Curly Bracket μ μ λ ₯νκ³ κ·Έ μμμ λ°°μ΄μ λ°λ³΅μ λλ©΄μ tweet νλ νλ λ§λ€ μ΄λ»κ² μ΄λ»κ² κ°κ³΅μ ν κ²μ΄λ€.
<ul id="tweets">
{this.state.tweets.map(tweet => {
return <SingleTweet />
})}
</ul>
λ 리ν΄ν κ±΄κ³ νλ SingleTweet μ΄λΌλ μ»΄ν¬λνΈλ₯Ό 리ν΄ν κ±°λΌ νλ€.
κ·Έλ¦¬κ³ SingleTweet μ»΄ν¬λνΈμ μΈ κ°μ§ μμ±μ μ§μ ν΄ μ£Όμλ€.
<ul id="tweets">
{this.state.tweets.map(tweet => {
return (
<SingleTweet
writer={tweet.writer}
date={tweet.date}
content={tweet.content}
/>
)
})}
</ul>
κ·Έλ΄λ― ν΄μ‘λ€. writer, date, content μμ±μ΄ μκ³ μμ± κ°μΌλ‘λ λ€μ Curly bracket μΌλ‘ λ°λ³΅ μμ νλ νλμ writer, date, content λ₯Ό λ°μ λ£μλ€.
μ΄μ render ν¨μλ λ΄λΆμ μΌλ‘ SingleTweet μ΄λΌλ μ»΄ν¬λνΈκ° μ΄λ»κ² μ μ λμ΄ μλμ§ κ·Έ 본체λ₯Ό μ°ΎμΌλ¬ κ°λ€.
μ€ λκ° λ ꡬ체μ μΌλ‘ μκ²Όλ€. 본체λ λ ꡬ체μ μ΄κ΅¬λ.
li νκ·Έλ₯Ό 리ν΄νλλ° λ΄λΆμ μΈ κ°μ div νκ·Έκ° μ리νκ³
κ°κ°μ content μμμ μμ μ μνλ writer, date, content μμ±μ props λ₯Ό ν΅ν΄ λ°μ λ£λλ€.
function SingleTweet(props) {
return (
<li>
<div>{props.writer}</div>
<div>{props.date}</div>
<div>{props.content}</div>
</li>
)
}
μ΄μ νΈμ νλ λΉ μμ κ°μ ννλ‘ λ¦¬ν΄λλ€.
μ΄μ λ textarea μ κΈμλ₯Ό μ λ ₯ν΄λ³Ό μ°¨λ‘μ΄λ€.
μ΄μ κΈ°λ³Έ λ°μ΄ν°λ₯Ό 보μ¬μ£Όλ λ°μλ μ±κ³΅νμΌλ μ΄μ μ textarea μ κΈμλ₯Ό νλμ© μ λ ₯ν λλ§λ€ κ°μ΄ λ€μ΄κ°κ² ν΄λ³΄μ.
κΈμκ° λ€μ΄κ°μ νλ©΄μ 보μ¬μ§λ 건 μΌλ¨ 미루κ³
λ¨Όμ κ°μ΄ λ€μ΄κ°λ€λ κ²μ λ λμΌλ‘ νμΈ ν΄λ΄μΌ κ² λ€.
νΈμ λ΄μ© (κ°) μ μ λ ₯νκ³ λ΄μ©μ μΆκ°ν΄μ νλ©΄μ 보μ¬μ§κ² νλ κ² μμ²΄κ° state κ°μ²΄λ₯Ό μμ νλ νμμ κ°λ€.
κ·Έλμ state λ΄ tweets λΌλ ν€ λ€μμΌλ‘ value λΌλ ν€λ₯Ό λ§λ€κ³ λΉ λ¬Έμμ΄μ λμλ€.
this.state.value = "" λ
μ°λ¦¬κ° μ λ ₯νλ ν μ€νΈκ° μ μ λ¨Έλ¬Όλ€ κ° ν΄κ²μ κ°μ λλμ΄λ€.
class Twittler extends React.Component {
constructor(props) {
super(props)
this.state = {
tweets: [
{
uuid: 1,
writer: 'μ νμ΄π',
date: '2020-11-19',
content: '리μ‘νΈλ μ΄λ?',
},
{
uuid: 2,
writer: '건λ§μ§μπ¨π»β',
date: '2020-11-19',
content: 'Not easy for me..π',
},
],
value: '', // μμ ν΄κ²μ
}
}
}
κ·Έλ¦¬κ³ ν΄λμ€ λ΄λΆμ textarea μ μν λ³κ²½μ μν (setState) ν¨μ handleChange λ₯Ό μ μΈνλ€.
handleChange(event) {
this.setState({ value: event.target.value });
}
document.querySelector(β#new-tweet-contentβ).value λ₯Ό ν΅ν΄ μ λ ₯ν κ°μ νμΈν μ μλ€.
μ΄λ₯Ό event.target.value λ‘ λ°μμ state κ°μ²΄μ value ν€κ° λ§μ λ°κΎΈμ΄ μ£Όμλ€.
κ·Έλ¦¬κ³ contructor μμ handleChange μ΄ window κ°μ²΄λ₯Ό κ°μ Έλ€μ°μ§ μκ² bind λ‘ κ³ μ ν΄μ€λ€.
class Twittler extends React.Component {
constructor(props) {
super(props)
this.state = {
tweets: [
{
uuid: 1,
writer: 'μ νμ΄π',
date: '2020-11-19',
content: '리μ‘νΈλ μ΄λ?',
},
{
uuid: 2,
writer: '건λ§μ§μπ¨π»β',
date: '2020-11-19',
content: 'Not easy for me..π',
},
],
value: '', // μμ ν΄κ²μ
}
}
this.handleChange = this.handleChange.bind(this);
}
λ§μ§λ§μΌλ‘ render() ν¨μ λ΄μ textarea νκ·Έμ onChange μ΄λ²€νΈλ₯Ό κ±Έμ΄μ€λ€.
JSX λ¬Έλ²μ μΈ λλ 컬리 λΈλΌμΌ μ μ¨μ μμ λ£μ΄μ£Όλ κ²μ μμ§ λ§μ.
<textarea
id="new-tweet-content"
cols="30"
rows="3"
onChange={this.handleChange}
value={this.state.value} // μλ μμ¨μ€λ λ κ±°κ°μλ° μ ννλ λͺ¨λ₯΄κ² λλ€.
></textarea>
κ·Έλ¦¬κ³ React Developer Tools λ₯Ό λ°κ³
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
npm start λ‘ μλ²λ₯Ό λλ € λμ€λ νμ΄μ§μμ κ°λ°μ λꡬλ₯Ό μ΄κ³ ,
react λͺ¨μ Components λ₯Ό λλ₯΄λ©΄ props, state λ±μ νμΈνκΈ° μ’λ€.
state κ°μ²΄ λ΄ value μ λ΄κ° μ λ ₯ν κ°μ΄ λ€μ΄κ° κ²μ νμΈν μ μλ€.
μ΄μ λ λ²νΌμ ν΄λ¦νμ λ, λ΄κ° μ λ ₯ ν μμ κ°μ΄ μ€μ λ‘ this.state.tweets λ°°μ΄μ κ°μ²΄ ννλ‘ λ€μ΄κ°κ²λ ν΄μ€μΌ νλ€.
React Dev Tools λ₯Ό μ¨μ μ§μ ν value μ λ΄κ° μ¨λ£μ λ©μμ§κ° λ€μ΄κ°λλ‘ ν κ±°λ μκ±° κ°λ€.
μ΄μ μ΄ μμ μ μ₯μ μ μ μ₯ν λ΄μμ μ€μ λ°°μ΄μ κ°μ²΄ ννλ‘ λ΄μ λ£μ΄ μ£Όμ΄μΌ νλ€.
handleClick μ΄λΌλ ν¨μλ₯Ό λ§μ°¬κ°μ§λ‘ class λ΄μ λ§λ€μ΄ μ€λ€.
handleClick(val) {
// val μ 9μμ λ£μ μ€μ νμ μΉ κ·Έ κ°μ΄ λ€μ΄κ°λ κ±°λ€.
// mockdata μ ννμ κ°μμΌ νλκΉ λ² κ»΄μ€μ, μ°κΈ° μ½κ² λ³μμ λ΄κ³ !
let newTweet = {
uuid: this.state.tweets.length + 1, // λ°°μ΄μκΈΈμ΄ + 1
writer: "CodeTasteJung",
date: new Date().toLocaleString(),
content: val,
};
}
μΈμλ‘ λ€μ΄κ°λ val μ μκΉ μ€μ νμ΄ννκ² μμν΄κ²μμ μ μ₯λ κ·Έ κ° (this.state.value) μ μλ―Ένλ€.
κ·Έλ¦¬κ³ λͺ©μ λ°μ΄ν°μ λκ°κ² newTweet μ΄λΌλ κ°μ²΄λ₯Ό νλ μ μΈν΄ μ£Όκ³ ,
κ·Έ μμ ν€μ κ°λ€μ λ£λλ€. content μμμλ νλΌλ―Έν°λ‘ λ°μ κ·Έ κ° val μ λ£μ΄μ€λ€.
κ·Έλ¦¬κ³ setState λ‘ μ 체 tweets λ°°μ΄μ μνλ₯Ό μ€μ νλ€.
κΈ°μ‘΄μ μλ mockup data νλ¬μ€ newTweet κ°μ²΄λ₯Ό μΆκ°λ‘ λ£μ΄μ£Όλ κ²μ΄λ€.
this.setState({ tweets: [...this.state.tweets, newTweet] })
this.setState({ value: '' })
κ·Έλ¦¬κ³ λ§μ§λ§μΌλ‘ μμ ν΄κ²μμΈ value μ κ°μ λ€μ μ΄κΈ°ν μμΌ λλλ€.
λ€λ₯Έ κ°λ€λ λ€μ΄ μ€κ²λ ν΄μΌ νλκΉ.
κ·Έλ¬λ©΄ handleClick μ μ½λλ μλμ κ°κ² λλ€.
handleClick(val) {
// val μ 9μμ λ£μ μ€μ νμ μΉ κ·Έ κ°μ΄ λ€μ΄κ°λ κ±°λ€.
// mockdata μ ννμ κ°μμΌ νλκΉ λ² κ»΄μ€μ, μ°κΈ° μ½κ² λ³μμ λ΄κ³ !
let newTweet = {
uuid: this.state.tweets.length + 1, // λ°°μ΄μκΈΈμ΄ + 1
writer: "CodeTasteJung",
date: new Date().toLocaleString(),
content: val,
};
this.setState({ tweets: [...this.state.tweets, newTweet] })
this.setState({ value: '' })
}
λ§μ°¬κ°μ§λ‘ constructor λ΄μ ν¨μ λ°μΈλ© ν΄μ£Όκ³
this.handleClick = this.handleClick.bind(this)
λ²νΌ νκ·Έλ₯Ό μ°Ύμμ onClick μ΄λ²€νΈλ₯Ό κ±Έμ΄ μ€λ€.
<button
id="submit-new-tweet"
onClick={() => {
this.handleClick(this.state.value)
}}
>
μ κΈ μ°κΈ°
</button>
μμ§ μ νν κΈ΄κ°λ―Όκ° νμ§λ§ μ²μμλ onClick λ΄ ν¨μλ₯Ό μ΄λ»κ² μ²λ¦¬ν΄ μ£Όμ΄μΌ νλ μΆμλ€.
μΌλ¨ λ°μλ€μ΄μ..
import React from 'react'
import './App.css'
class Twittler extends React.Component {
constructor(props) {
super(props)
this.state = {
tweets: [
{
uuid: 1,
writer: 'μ νμ΄π',
date: '2020-11-19',
content: '리μ‘νΈλ μ΄λ?',
},
{
uuid: 2,
writer: '건λ§μ§μπ¨π»β',
date: '2020-11-19',
content: 'Not easy for me..π',
},
],
value: '',
}
this.handleChange = this.handleChange.bind(this)
this.handleClick = this.handleClick.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleClick(val) {
let newTweet = {
uuid: this.state.tweets.length + 1,
writer: 'CodeTasteJung',
date: new Date().toLocaleString(),
content: val,
}
this.setState({ tweets: [...this.state.tweets, newTweet] })
this.setState({ value: '' })
}
render() {
return (
<div>
<div>μμ±μ: π¨π»βπDev-Seolleung2π¨π»βπ</div>
<div id="writing-area">
<textarea
id="new-tweet-content"
cols="30"
rows="3"
onChange={this.handleChange}
value={this.state.value}
></textarea>
<button
id="submit-new-tweet"
onClick={() => {
this.handleClick(this.state.value)
}}
>
μ κΈ μ°κΈ°
</button>
</div>
<div>
<ul id="tweets">
{this.state.tweets.map(tweet => {
return (
<SingleTweet
writer={tweet.writer}
date={tweet.date}
content={tweet.content}
/>
)
})}
</ul>
</div>
</div>
)
}
}
function SingleTweet(props) {
return (
<li>
<div>{props.writer}</div>
<div>{props.date}</div>
<div>{props.content}</div>
</li>
)
}
export default Twittler