본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[87일차]20210714 Context로 댓글 만들기 (with 리액트식으로 컴포넌트 구성하기)

반응형

 

오늘 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 사용해서 댓글 추가하기 끝 ! 

반응형