[Code Camp_TIL] 230320 DAY6

23·2023년 3월 20일
0

FrontEnd TIL

목록 보기
6/13
post-thumbnail

🎯 수업 목차

  1. 실무용 폴더 구조
  2. props
  3. export vs export default

👩🏻‍💻 오늘의 TIL

실무용 폴더구조

프로젝트를 만들 때 폴더 구조는 매우 중요하다.
여럿이서 협업을 하거나 혼자 작업하더라도 구조를 잘 정리해두어야 일의 능률도 오르기 때문이다.
실무에서 사용하는 폴더 구조는 여러 가지 방법이 존재하는데, 이러한 방법들을 패턴이라고 부른다.
React에서 사용하는 유명한 패턴으로는 container / presenter 패턴, hooks 패턴, atomic 패턴 등이 있다.

1. container / presenter 패턴

container / presenter 패턴이란, 소스코드를 자바스크립트(기능)JSX (UI)로 나누는 방법을 의미한다.

여기서 container는 자바스크립트(기능) 부분을 의미하고, presenter은 JSX(UI) 부분을 의미한다.

❗️ 파일을 나누었어도 _app.js에서 실행될 때에는 컴포넌트들이 합쳐져서 실행되어야 한다!!


예제

1. presenter.js

export default function ProductCreateUI (props) {
    return(
        <>
            판매자: <input type="text" onChange={props.onChangeSeller}></input><br></br>
            이름: <input type="text" onChange={props.onChangeName}></input><br></br>
            제품 설명: <input type="text" onChange={props.onChangeDetail}></input><br></br>
            가격: <input type="text" onChange={props.onChangePrice}></input><br></br>
            <button onClick={props.onClickBtn}>GRAPHQL-API 요청하기</button>
        </>
    )
}

return() 안에 작성하는 JSX 방식 HTML 부분이다.
페이지를 구성하는 부분이기 때문에 함수 이름 뒤에 UI를 붙인다.
가장 하위의 자식 컴포넌트이다.

2. container.js

import { useMutation, gql } from "@apollo/client";
import { useState } from 'react'
import { useRouter } from 'next/router'
import ProductCreateUI from "./ProductCreate.presenter"
import { CREATE_PRODUCT } from "./ProductCreate.queries"

  export default function ProductCreate () {
    const [submitFn] = useMutation(CREATE_PRODUCT)
    const router = useRouter()
    const [ seller, setSeller] = useState("")
    const [ name, setName] = useState("")
    const [ detail, setDetail] = useState("")
    const [ price, setPrice] = useState("")

    const onChangeSeller = (event) => {
        setSeller(event.target.value)
    }
    const onChangeName= (event) => {
        setName(event.target.value)
    }
    const onChangeDetail = (event) => {
        setDetail(event.target.value)
    }
    const onChangePrice = (event) => {
        setPrice(event.target.value)
    }

    const onClickBtn = async () => {
        try{
            const result = await submitFn({
                variables: {
                    seller: seller,
                    createProductInput: {
                        name: name,
                        detail: detail,
                        price: Number(price)
                    }
                }
            })
            router.push(`/06/products/moved/${result.data.createProduct._id}`)
        }catch(error){
            alert(error.message)
        }
    }

    return(
        <ProductCreateUI
        onChangeSeller={onChangeSeller}
        onChangeName={onChangeName}
        onChangeDetail={onChangeDetail}
        onChangePrice={onChangePrice}
        onClickBtn={onClickBtn}
        />
    )
}

자바스크립트 기능과 함수를 작성하는 부분이다.
자식인 presenter.jsimport하여 return() 안에 넣어준다.
그 외에 기능에 필요한 라이브러리 등도 이곳에서 import 해준다.

3. queries.js

const { gql } = require("@apollo/client")

export const CREATE_PRODUCT = gql`
        mutation CREATE_PRODUCT($seller: String, $createProductInput: CreateProductInput!){
            createProduct(
                seller: $seller
                createProductInput: $createProductInput
            ){
                _id
                number
                message
            }
        }
    `

api 요청 함수 등을 작성하는 부분이다.
컴포넌트는 아니며 gql 등 필요한 라이브러리를 이곳에서 import 한다.

4. index.js

import ProductCreate from "/src/components/units/products/create/ProductCreate.container";

export default function GraphqlQuiz (){
   
    return(
        <ProductCreate/>
    )
}

페이지를 실행하면 접속 경로인 주소값을 가지고 있는 폴더이다.
container.js를 import하여 return() 안에 넣어준다.

5. _app.js

import '/styles/globals.css'
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'

export default function App({ Component }) {
  const client = new ApolloClient({
    uri: "http://backend-example.codebootcamp.co.kr/graphql",
    cache: new InMemoryCache(),
  })

  return (
    <ApolloProvider client={client}>
      <Component/> 
    </ApolloProvider>
  )
}

최종적으로 컴포넌트들이 조립되어 실행되는 페이지이다.
가장 상위의 부모이다.
모든 페이지에서 공통적으로 사용할 라이브러리나 스타일 등을 import 한다.


💡 부모 컴포넌트와 자식 컴포넌트

import 되어 불려가는 컴포넌트를 자식 컴포넌트라고 한다.
반면 import하여 불러오는 컴포넌트를 부모 컴포넌트라고 한다. 자식 컴포넌트는 부모 컴포넌트 안에 포함되는 구조이다.


props

컴포넌트를 나누게 되면, 데이터와 기능의 연결고리가 끊어지게 된다.
이를 props가 연결해주게 되며, props란 부모 컴포넌트가 자식 컴포넌트에게 물려주는 변수 / 함수 를 의미한다.
부모 컴포넌트가 props를 물려줄때는 객체로 묶어서 넘기게 된다!!

props를 내려주기 _ 부모 컴포넌트

//부모 컴포넌트 _ container 부분

const BoardWrite = ()=>{
		const [writer, setWriter ] = useState()
		const handlechangeWriter = (e)=>{
					writer = e.target.value
					setWriter(writer)
						}

	return(
		// 자식 컴포넌트 _ presenter 컴포넌트 
		// 본격적으로 props를 내려주는 부분입니다.
		<BoardWriteUI propsName={handlechangeWriter}/>
	)
}

위와 같이 props를 넘기게 되면, props = { propsName : handlechangeWriter } 형태의 객체로 넘어가게 된다.
또한 props는 여러 개를 내려줄 수 있다.

props 받아오기

//자식컴포넌트 _ presenter 부분

//파라미터 부분에 props를 적어주셔야 받아 올 수 있습니다.
const BoardWriteUI = (props)=>{
		return(
			<Wrapper>
				<Writer
					type = "text"
					placeholder = "작성자를 적어주세요"
					// 본격적으로 props를 내려받는 부분입니다.
					onChange = {props.propsName}
					/>
			</Wrapper>
		)
}

파라미터 부분에 props를 적지 않으면 받아올 수 없으니 주의!!

또한 객체로 넘어오기 때문에 받아온 props를 사용하려면 객체의 속성을 꺼내오는 것처럼 사용해야 한다. 따라서 props.propsName 형태로 사용해야 한다!

💡 props 구조 분해 할당으로 받아오기

구조 분해 할당으로 props를 받아오게 되면, props.propsName이 아닌 propsName만 적으면 되기 때문에 조금 더 편리하게 사용할 수 있다.

또한 , 구조 분해 할당으로 props를 받아오면 필요한 것만 받아올 수 있다!
부모 컴포넌트는 하나지만, 자식 컴포넌트가 여러 개인 경우 구조분해 할당이 props를 내려주고 받는데 더 편리하다.

//구조분해 할당으로 props 받아오기 

//기존 파라미터 부분에는 props라고 적어 props의 모든것을 받았습니다.
export const function BoardWrite({handleInput, handleChange}){

//기존 방법은 props.handleInput , props.handleChange 입니다. 
<input onChange={handleInput}
<button onClick={handleChange}
}

💡 리액트의 단방향 데이터 흐름

리액트는 데이터 흐름이 단방향 구조이다.
데이터 흐름이 단방향 구조라는 것은 props는 부모가 자식에게만 줄 수 있으며, 자식이 부모에게 줄 수 없다는 것을 의미한다.
React의 데이터 흐름이 단방향 구조이기 때문에 에러를 캐치하기가 더 쉽고, 보기에 더 깔끔하다.


export vs export default

import를 할 때, 중괄호를 사용해서 데리고 오는 것이 있는가 하면, 중괄호 없이 데리고 오는 것이 있다.
중괄호의 사용 여부는 export를 하냐 export default를 하느냐에 따라 결정된다.

export를 사용하게 되면 한 컴포넌트 내에서 여러 개를 내보내기 때문에 중괄호를 사용해 필요한 것들만 import 된다.

하지만 export default를 사용하게 되면 한 컴포넌트에서 한 개만 내보내기 때문에 중괄호를 사용하지 않고 import 하게 된다.

💡 export vs export default

export

  • 중괄호를 사용해서 import 해온다.
  • 한 컴포넌트 내에서 여러 개를 내보낼 때 사용한다.
  • import 해올 때는 export한 이름 그대로 불러와야 한다!!
  • 한번에 묶어서 import 할 시에는 import * as S from ‘경로’ 라고 표현할 수 있다. (S는 원하는 이름으로 지정가능)

export default

  • 중괄호 없이 import 해온다.
  • import 해올 때 export 한 이름이 아니어도 괜찮다!!
  • 한 컴포넌트에서 한개만 export했기 때문에 파일의 경로만 제대로 지정되면 이름이 어떤것이든 상관없이 잘 불러온다.

atomic 패턴

atomic 패턴이란, 소스 코드를 아주 작은 컴포넌트 단위로 먼저 쪼개는 방법을 의미한다.
이렇게 하는 이유는 컴포넌트의 중복을 최소화하기 위해서이다.
총 5개의 폴더 구조로 이루어지며, 각각의 의미는 화학의 원리를 이용하여 만든다.

atoms, molecules, organisms, templates, pages 이렇게 5개의 폴더로 나누어서 컴포넌트들을 관리한다.
atomic 패턴은 디자이너들의 세계에서도 널리 알려진 패턴이며 atomic 패턴을 사용하면 디자이너들과의 협업에 유리해질 수 있고, 프로젝트 시작부터 체계적인 UI적 설계가 가능해진다.

하지만, 프로젝트 시작부터 UI를 디자이너와 함께 전체적으로 설계해야하므로 실제 개발준비까지 걸리는 시간이 오래 걸릴 수 있다.

따라서, 시간, 비용, 팀의 상황 등에 따라서 적용하는 것이 일반적이다!!


💡 알게된 것

  • 프로젝트에서 폴더 구조를 나누는 방법이 궁금했는데 다양한 규칙에 따라 구조를 나눌 수 있다는 것을 알았다!
  • React JSX로 toggle 버튼을 만드는 법을 알았다. 혼자 구현한 방법과 멘토님의 조언으로 구현한 방법 둘 다 잘 터득해놔야겠다.
  • import * as S from ‘경로’ 방식을 사용하면 style-component를 import하기 훨씬 편할 것 같다!!

🤔 궁금한 것

  • 한 페이지만이 아닌 모든 페이지에서 공통으로 사용하는 컴포넌트는 어떻게 모아두는지 궁금하다.
  • hooks 패턴으로 나누는 구조가 궁금하다.

💖 느낀 점

2주차가 시작되었다! 오늘의 수업은 오랜 궁금증 중 하나였던 폴더 나누는 법에 대한 내용이였다.
많은 개발자들이 자주 사용하는 패턴에 대해 배우고 직접 적용해보는 실습을 해보았다.
아직은 작은 규모의 페이지들이다보니 지금 구조화를 해도 더 효율적인건지 체감이 잘 안되지만 훨씬 규모가 커지면 분명 체감이 들겠지?
늘 코드를 좀 더 착착 정리할 수는 없는 것인가!? 의문을 가지며 코드를 짜왔기 때문에 일단은 정리를 하는 방법에 대해 배운 것 만으로도 만족이다.
앞으로는 폴더 분리 패턴에 따라 잘 정리하면서 코드를 작성하는 습관을 들여야겠다~!
이번 주도 무사히 공부하자!!

profile
프론트엔드 개발자가 꿈인 고슴도치

0개의 댓글