오늘 Context를 사용해서 댓글 기능 만들기 !
1. Components 구성하기 (위 파일트리대로 만들기 / 기본 코드 작성 + 서로 연결)
Layout은 ul 로 감싸기 / form, List는 li tag로 !
Comment.jsx
import React from 'react'
import CommentLayout from './CommentLayout'
import CommentForm from './CommentForm'
import CommentList from './CommentList'
const Comment = () =>{
return(
<>
<CommentLayout>
<CommentForm/>
<CommentList/>
</CommentLayout>
</>
)
}
export default Comment
CommentLayout은 children을 써야한다는 걸 알 수 있다.
CommentLayout.jsx
import React from 'react'
const CommentLayout = ({ children }) => {
return (
<>
<ul>
{children}
</ul>
</>
)
}
export default CommentLayout
CommentForm.jsx
import React from 'react'
const CommentForm = () => {
return (
<>
<li>
Form Component
</li>
</>
)
}
export default CommentForm
CommentList.jsx
import React from 'react'
const CommentList = () =>{
return(
<>
<li>
List Component
</li>
</>
)
}
export default CommentList
-> 컴포넌트 디자인 , 구조 잘 생각해서 만들기
CommentLayout으로 Form, List를 감싸고 있어서 두 개의 자리를 자유롭게 바꿀 수 있음
2. css 연결하기 (component > css > index.css)
웹팩이 처음 실행되면 index.jsx 만 읽는다 index.jsx -> App.jsx -> Comment ... 연결된 걸 찾는 것 ! !
css 파일 어디다두어도 상관없음 ! 가장 최초인 index.jsx 에 하자 -> css 잘 연결되었는지 확인
index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './css/index.css'
ReactDOM.render(
<App/>,
document.querySelector('#root')
)
html의 css 잘 적혀있는지 확인
index.html
<link rel="stylesheet" href="./dist/app.css">
css는 요거 사용하기 ↓↓↓
*{margin:0; padding:0;}
body{
font-family: 'Noto Sans KR', sans-serif;
font-weight:300;
}
ul,li{
list-style:none;
}
.comment{
display:flex;
flex-direction: column;
flex-wrap: nowrap;
padding:30px;
width:600px;
margin:0 auto;
}
.comment > li{ margin-top:20px; }
.comment > li:nth-child(1){ margin:0px;}
.comment-row{
display:flex;
justify-content: space-between;
flex-direction: row;
}
.comment-row{
margin-top:20px;
width:100%;
}
.comment-row > li:nth-child(2){
flex-shrink: 0;
flex-grow: 1;
padding-left:25px;
z-index:1;
width:100%;
}
.comment-row > li:nth-child(2){
width:85px;
}
.comment-form > form{
display:flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
.comment-form > form > h4{
width:100%;
margin:14px 0 14px 0;
}
.comment-content{
word-break:break-all;
padding-right:25px;
}
.ps_box{
display: block;
position: relative;
width: 80%;
height: 51px;
border: solid 1px #dadada;
padding: 10px 14px 10px 14px;
background: #fff;
box-sizing: border-box;
}
.ps_box > input{
outline:none;
}
.int{
display: block;
position: relative;
width: 100%;
height: 29px;
padding-right: 25px;
line-height: 29px;
border: none;
background: #fff;
font-size: 15px;
box-sizing: border-box;
z-index: 10;
}
.btn{
width:18%;
padding: 18px 0 16px;
text-align: center;
box-sizing: border-box;
text-decoration: none;
border:none;
background:#333;
color:#fff;
font-size:14px;
}
.comment-delete-btn{
display:inline-block;
margin-left:7px;
cursor: pointer;
}
.comment-update-input{
border:none;
border-bottom: 1px solid #333;
font-size:16px;
color:#666;
outline: none;
}
3. 화면 꾸미기
CommentForm.jsx
import React from 'react'
const CommentForm = () => {
return (
<>
<li className="comment-form">
From Component
<form>
<span className="ps_box">
<input
type="text"
className="int"
placeholder="댓글을 입력해주세요"
/>
</span>
<button
type="submit"
className="btn"
>
등록
</button>
</form>
</li>
</>
)
}
export default CommentForm
CommentList.jsx
list안에 CommentItem이라는 컴포넌트를 만들기
import React from 'react'
import CommentItem from './CommentItem'
const CommentList = () =>{
return(
<>
<li>
<CommentItem
userid="아이디1"
content="댓글1"
data="2021-07-14"
/>
<CommentItem
userid="아이디2"
content="댓글2"
data="2021-07-15"
/>
<CommentItem
userid="아이디3"
content="댓글3"
data="2021-07-16"
/>
</li>
</>
)
}
export default CommentList
CommentItem.jsx
import React from 'react'
const CommentItem = ({userid,content,date}) => {
return (
<>
<ul className="comment-row">
<li className="comment-id">{userid}</li>
<li className="comment-content">{content}</li>
<li className="comment-date">{date}</li>
</ul>
</>
)
}
export default CommentItem
item의 내용 계속 바꾸기
List에서 배열로 받은 걸 위처럼 뿌리려면?
여기까지 리액트처럼 생각해서 컴포넌트 나누기 끗 ! 다음에 참고하자
개념 설명 TIME
DOM 이란 ? - > 복습 때 정리하기 !
≒ HTML ?
< > markup 처음에 열리고 닫히는 곳까지 DOM - > element or tag 라고도 표현함 -> JS로 요 해당 element를 조작하는 행위를 (or css 조작) DOM 조작이라고 부른다고 하심 !
Context 개념 설명
Context라는 저장소에 정보를 저장하고 각각의 컴포넌트에서 필요한 정보 요청 -> 바로 줄 수 있다.
기능 : 읽기! 만 가능 context야 ~ 내용 바꿔줘 ! - > 안됨
그래서 같이 사용하는게 Reducer (Reducer는 함수와 상태값을 보냄. )
Context 가[state, dispatch] 를 가지고 있고 이걸 보내주면 내용을 수정할 수 있다.
JS, 리액트는 {}=={} -> false (충격) -> 이걸 true 로 바꾸는게 불변성의 법칙
{}=={} 다른 이유 : 저장되는 메모리 주소가 다름
값을 변경하는데 값이 똑같아서 rerender를 안하게됨
그래서 불변성의 법칙이 필요 -> reactDOM이 false값을 인지하고 변경된 값을 넣으려고
얇은 복사로 ...state (관계 끊기)
그래서 어제 ...state 가 있었던 것 !!!!!!!!!!! 의문점 해결
4. Context, Reducer 만들기
comment > store 폴더 생성 > context 파일 , reducer 파일 만들기
Context 안에서 데이터 저장이 이루어지도록 하는게 좋음 -> 데이터 관리
Component에 데이터 저장은 추천 X ! -> 화면 이쁘게 꾸미고 잘 나타내기 + 효율적인 구성
두 역할이 확실히 구분됨
context.jsx
import React from 'react'
const initialState ={
commentItem:[
{userid:'ID입니다', content:'댓글1', date:'2021-07-14'}
]
}
const Store = React.createContext(initialState) // context 생성
// 인자값으로 default값
export default Store
reducer.jsx (dispatch가 실행되면 실행됨, 미리 만들어 놓기 !)
// reducer가 바꿀 상태 state -> 이전 상태값 가져와야함
// dispatch가 바꿀 정보를 줄꺼야 -> 두번째 인자값 action으로 받음
// 최종적으로 reducer는 수정된 state 값을 보내줌
const reducer = (state, action) => {
switch (action.type) {
case 'CREATE':
return {
...state,
}
case 'UPDATE':
return {
...state,
}
case 'DELETE':
return {
...state,
}
default:
return{
...state,
}
}
}
export default reducer
저기서 ... 없이 state만 쓰이면 변경이 안된다. ! (수정이 되어도) 꼭 ...state로 쓰기 !
5. Layout에서 context, reducer 가져오기 ,Context 사용하기
import React, {useContext} from 'react'
import Store from './store/context'
import reducer from './store/reducer'
const CommentLayout = ({ children }) => {
const globalStore = useContext(Store) // context 사용할 때는 use
//여기서 인자값 Store 들어오는 거 잘 분석하기 !
// store 에서 export 하는거 내용 잘 봐
console.log(globalStore)
return (
<>
<ul className="comment">
{children}
</ul>
</>
)
}
export default CommentLayout
console.log에 잘 찍힘
6. reducer 가져오기, 사용하기
import React, {useContext, useReducer} from 'react'
import Store from './store/context'
import reducer from './store/reducer'
const CommentLayout = ({ children }) => {
const globalStore = useContext(Store) // context 사용할 때는 use
//여기서 인자값 Store 들어오는 거 잘 분석하기 !
// store 에서 export 하는거 내용 잘 봐
console.log(globalStore)
const [state,dispatch] = useReducer(reducer,globalStore)
console.log('state value = ', state)
return (
<>
<ul className="comment">
{children}
</ul>
</>
)
}
export default CommentLayout
7. 하위 컴포넌트들에게 전달하기
import React, { useContext, useReducer } from 'react'
import Store from './store/context'
import reducer from './store/reducer'
const CommentLayout = ({ children }) => {
const globalStore = useContext(Store) // context 사용할 때는 use
//여기서 인자값 Store 들어오는 거 잘 분석하기 !
// store 에서 export 하는거 내용 잘 봐
console.log(globalStore)
const [state, dispatch] = useReducer(reducer, globalStore)
console.log('state value = ', state)
return ( // Store.provider ~ 로 감싸면 이제 하위 컴포들에게 값(value)를 보내줄 수 있음
<>
<Store.Provider value={{state,dispatch}}>
<ul className="comment">
{children}
</ul>
</Store.Provider>
</>
)
}
export default CommentLayout
요기까지하면 하위 컴포넌트들이 쓸 수 있음
8. commentForm 에서 Context 사용하기
- Store, useContext 가져오기
CommentForm.jsx
import React, {useContext} from 'react'
import Store from './store/context'
const CommentForm = () => {
console.log(useContext(Store))
비구조 할당문으로 가져와서 console.log찍어보기
import React, {useContext} from 'react'
import Store from './store/context'
const CommentForm = () => {
const {state,dispatch} = useContext(Store)
console.log(state,dispatch)
return (
<>
9. input box에 입력한 value state로 담아서 onChange 되도록 만들기 = > dispatch 보내기
import React, {useContext, useState} from 'react'
import Store from './store/context'
const CommentForm = () => {
const [input, setInput] = useState('')
const {state,dispatch} = useContext(Store)
console.log(state,dispatch)
const handleChange = e =>{
const {value} = {...e.target}
setInput(value)
}
const handleSubmit = e =>{
e.preventDefault()
dispatch({type:'CREATE', payload:{userid:'ID이다', content:input,date:'2021-07-14'}, })
setInput('')
}
return (
<>
<li className="comment-form">
Form Component
<form onSubmit={handleSubmit}>
<span className="ps_box">
<input
type="text"
className="int"
placeholder="댓글을 입력해주세요"
onChange={handleChange}
value={input}
/>
</span>
<button
type="submit"
className="btn"
>
등록
</button>
</form>
</li>
</>
)
}
export default CommentForm
10. reducer.jsx 수정
// reducer가 바꿀 상태 state -> 이전 상태값 가져와야함
// dispatch가 바꿀 정보를 줄꺼야 -> 두번째 인자값 action으로 받음
// 최종적으로 reducer는 수정된 state 값을 보내줌
const reducer = (state, action) => {
console.log('action',action)
switch (action.type) {
case 'CREATE':
return {
...state, // 다른 값들 넣을 때 대비해서 일단 넣어두기
commentItem:[...state.commentItem, action.payload]
}
case 'UPDATE':
return {
...state,
}
case 'DELETE':
return {
...state,
}
default:
return{
...state,
}
}
}
export default reducer
commentList
import React, { useContext, useState } from 'react'
import CommentItem from './CommentItem'
import Store from './store/context'
const CommentList = () => {
const { state } = useContext(Store) // {state, dispatch}
const list = state.commentItem
const Item = list.map((v, k) => {
return (
<>
<CommentItem
key={k}
userid={v.userid}
content={v.content}
data={v.date}
/>
</>
)
})
return (
<li>
{Item}
</li>
)
}
export default CommentList
11. CommentItem.jsx
import React from 'react'
const CommentItem = ({userid,content,date}) => {
return (
<>
<ul className="comment-row">
<li className="comment-di">{userid}</li>
<li className="comment-content">{content}</li>
<li className="comment-date">{date}</li>
</ul>
</>
)
}
export default CommentItem
context 사용해서 댓글 추가하기 끝 !
'블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기' 카테고리의 다른 글
[88일차]20210715 리액트 댓글 수정 삭제 (0) | 2021.07.15 |
---|---|
[87일차 복습] 리액트 Context 사용해서 댓글 추가하기 (0) | 2021.07.14 |
[86일차 복습] React useReducer Context syled-component로 TicTacToe만들기 (0) | 2021.07.14 |
[86일차]20210713 리액트 useReducer Context styled-component Ref Css TicTacToe 만들기 (0) | 2021.07.13 |
[85일차 복습] React Hooks useMemo useCallback (0) | 2021.07.13 |