yarn init -y
package.json에 추가 코드 작성
"private": true,
"workspaces":[
"client",
"server"
],
"scripts": {
"client":"yarn workspace client start",
"server":"yarn workspace server start"
}
client, server 폴더 생성
cd client
yarn init -y
yarn add react react-dom next sass axios
yarn add --dev webpack
client/pages/index.js
// pages 폴더는 next.js에서 기반이 되는 폴더
const Home=()=>(
<>
<h1>Simple SNS</h1>
</>
)
export default Home
client/package.json
},
"scripts": {
"start": "next"
},
root폴더로 이동해서 yarn run client
localhost:3000 브라우저에서 확인하면
client/components/MsgList.js
import MsgItem from "./MsgItem"
/*
const MsgList=()=><ul className="message">{
[] 배열에 있는 정보를 임시로 mock데이터로
[].map(x=><MsgItem {...x}/>)
}</ul>
*/
const UserIds=['roy','jay']
const getRandomUserId=()=>UserIds[Math.round(Math.random())]
const msgs=Array(50).fill(0).map((_,i)=>({
id:50-i,
userId: getRandomUserId(),
timestamp: 1234567890123+50-i*1000*60,
text: `${50-i} mock text`
}))
const MsgList=()=>(
<ul className="message">
{msgs.map(x=>(
<MsgItem key={x.id} {...x} />
))}
</ul>
)
export default MsgList
client/components/MsgItem.js
const MsgItem=({userId,timestamp,text})=>(
<li className="message__item">
<h3>
{userId}{' '}
<sub>
{new Date(timestamp).toLocaleDateString('ko-XR',{
year:'numeric',
month: 'numeric',
day:'numeric',
hour:'2-digit',
minute:'2-digit',
hour12: true
})}
</sub>
</h3>
{text}
</li>
)
export default MsgItem
pages/index.js
// pages 폴더는 next.js에서 기반이 되는 폴더
import MsgList from "../components/MsgList"
const Home=()=>(
<>
<h1>Simple SNS</h1>
<MsgList />
</>
)
export default Home
pages/index.scss → 스타일 작성 (일단 생략)
pages/_app.js
import './index.scss'
// next가 서버사이드렌더링 하기 위해 필요, 기본 공식처럼 있으니까 그냥 따라하면 된다.
const App=({Component, pageProps})=><Component {...pageProps} />
App.getInitialProps=async({ctx,Component})=>{
const pageProps=await Component.getInitialProps?.(ctx)
return {pageProps}
}
export default App
client/next.config.js
const path=require("path")
module.exports={
sassOption:{
includePaths:[path.resolve(__dirname,'./pages')],
},
}
components/MsgInput.js
import { useRef } from 'react'
const MsgInput=({mutate})=>{
const textRef=useRef(null)
const onSubmit=e=>{
e.preventDefault()
e.stopPropagation()
const text=textRef.current.value
textRef.current.value=''
mutate(text)
}
return (
<form className='message__input' onSubmit={onSubmit}>
<textarea
ref={textRef}
placeholder="내용을 입력하세요."
/>
</form>
)
}
export default MsgInput
MsgList.js에 state가 바뀌는걸 반영
import MsgItem from "./MsgItem"
import { useState } from "react"
import MsgInput from "./MsgInput"
/*
const MsgList=()=><ul className="message">{
[] 배열에 있는 정보를 임시로 mock데이터로
[].map(x=><MsgItem {...x}/>)
}</ul>
*/
const UserIds=['roy','jay']
const getRandomUserId=()=>UserIds[Math.round(Math.random())]
const msgs=Array(50).fill(0).map((_,i)=>({
id:50-i,
userId: getRandomUserId(),
timestamp: 1234567890123+(50-i)*1000*60,
text: `${50-i} mock text`,
}))
const MsgList=()=>{
const [msgs,setMsgs]=useState(originalMsgs)
const onCreate=text=>{
const newMsg={
id:msgs.length,
userId: getRandomUserId(),
timestamp: Date.now(),
text: `${msgs.length+1} ${text}`
}
setMsgs(msgs=>([newMsg,...msgs]))
}
return (
<>
<MsgInput mutate={onCreate} />
<ul className="message">
{msgs.map(x=>(
<MsgItem key={x.id} {...x} />
))}
</ul>
</>
)
}
export default MsgList