React 재활훈련- 3일차, React jsx, props

0

react

목록 보기
3/11

React base

react의 component는 하나의 함수를 만들어서 html과 같은 tag들을 반환하는 것을 말한다.

import './App.css'

function App() {
  return (
    <>
      <h1>안녕 리액트</h1>
    </>
  )
}

export default App

다음과 같이 App 함수는 html tag를 리턴하고 있으므로, 이를 하나의 react component라고 할 수 있다. 또한 함수로 만들어졌으므로 함수형 컴포넌트라고 한다. 클래스로도 가능한데, 클래스 컴포넌트는 old-style이므로 추천하지 않는다.

Header component를 만들어보도록 하자.

const Header = () => {
  return (
    <header>
      <h1>
        heeader
      </h1>
    </header>
  )
}

다음과 같이 arrow function을 사용하여 Header component를 만들 수 있다.

이제 Header component를 rendering시켜주도록 하자.

function App() {
  return (
    <>
      <Header/>
      <h1>안녕 리액트</h1>
    </>
  )
}

App component의 child component로 Header를 넣어주었다. 이처럼 react component는 부모-자식 component 형식으로 구성된다.

재밌는 것은 Header는 javascript 함수인데 마치 html tag처럼 사용할 수 있다. 이는 Header 함수를 하나의 react component로 치부하기 때문이다.

react에서는 react component들을 한 곳에 묶어 놓고 관리한다. 따라서 우리의 Header component도 다른 파일에 관리하도록 하자.

src/components/Header.jsx를 만들도록 하자.

  • src/components/Header.jsx
const Header = () => {
    return (
        <header>
        <h1>
            heeader
        </h1>
        </header>
    )
}
  
export default Header

이제 Header component를 App.jsx에서 불러오도록 하자.

import './App.css'
import Header from "./components/Header"

function App() {
  return (
    <>
      <Header/>
      <h1>안녕 리액트</h1>
    </>
  )
}

export default App

import문으로 불러오면 된다. 아마 python 개발자들은 꽤 헷갈릴텐데 python은 from - import이지만 여기는 import - from이다.

Header component를 만들었으니, Body component도 만들도록 하자.

  • components/Body.jsx
function Body() {
    return (
        <div>
            <h1>Body</h1>
        </div>
    )
}

export default Body

Footer component도 만들자.

  • components/Footer.jsx
const Footer = () => {
    return (
        <div>
            <h1>Footer</h1>
        </div>
    )
}

export default Footer

마지막으로 FooterBody component를 App component에 써보도록 하자.

  • App.jsx
import './App.css'
import Header from "./components/Header"
import Body from './components/Body'
import Footer from './components/Footer'

function App() {
  return (
    <>
      <Header/>
      <Body/>
      <Footer/>
    </>
  )
}

export default App

이제 나란히 Hader Body, Footer가 렌더링 될 것이다.

JSX

  • components/Body.jsx
function Body() {
    return (
        <div>
            <h1>Body</h1>
        </div>
    )
}

export default Body

사실 javascript내에서 반환값으로 html tag를 반환하는 것은 불가능한 일이다. 이것이 가능한 일은 jsx문법 덕분이다. 즉, 순수한 js가 아니라 jsx이기 때문이다.

jsx는 javascript + xml 이라는 말로 html과 javascript를 합쳤다라고 생각하면 된다. 다음과 같이 javascript 변수도 렌더링할 수 있는데, {}를 사용하면 javascript 변수를 사용할 수도 있다.

function Body() {
    const number = 10;
    return (
        <div>
            <h1>Body</h1>
            <h2>{number}</h2>
        </div>
    )
}

export default Body

화면에 10이 렌더링 될 것이다.

또한, 덧셈과 같은 계산도 가능하고 삼항 연산자도 가능하다.

function Body() {
    const number = 10;
    return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
        </div>
    )
}

export default Body

또한 string문자열 역시도 넣을 수 있다.

function Body() {
    const number = 10;
    const hello = "hello"

    return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
        </div>
    )
}

export default Body

단, jsx는 문자열, 숫자값만 렌더링이 가능하니 조심하자, 즉 boolean값을 넣으면 렌더링되지 않는다.

만약, 객체를 넣으면 어떻게될까?

function Body() {
    const number = 10;
    const hello = "hello"
    const obj = {
        a: 1,
    }

    return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
            <h2>{obj}</h2>
        </div>
    )
}

export default Body

화면에 아무것도 나오지 않을 것이다. 이는 error가 발생했다는 것을 의미한다. 단, object의 property들이 문자열이나 숫자이면 렌더링 된다.

즉 다음과 같이 쓸 수 있다.

function Body() {
    const number = 10;
    const hello = "hello"
    const obj = {
        a: 1,
    }

    return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
            <h2>{obj.a}</h2>
        </div>
    )
}

export default Body

결론적으로 jsx에서는 javascript 표현식만 가능하다. 즉, 삼항연산자, 값 자체만 가능하지 다음 처럼 if문과 같은 것들은 불가능하다.

function Body() {
    const number = 10;
    const hello = "hello"
    const obj = {
        a: 1,
    }

    const func = () => {
        return "hello world"
    }

    return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
            <h2>{obj.a}</h2>
            <h2>{func()}</h2>
            <h2>{if ...}</h2>
        </div>
    )
}

export default Body

func와 같이 javascript함수가 표현식을 리턴한다면 문제가 없지만, if와 같이 javascript 표현식이 아닌 경우는 실행되지 않는다.

jsx문법에서는 모든 tag들이 최상위 tag들로 묶여 있어야 한다.

return (
        <div>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
            <h2>{obj.a}</h2>
            <h2>{func()}</h2>
            <h2>{if ...}</h2>
        </div>
    )

다음의 예제에서 <div></div>h2 tag들이 모두 묶여 있는 것을 볼 수 있다. div tag를 없애면 최상위 tag인 <div>가 없으면 에러가 발생한다. 만약 <div>와 같이 특정 tag를 최상위 tag로 쓰고 싶지 않다면 <>를 사용하면 된다.

return (
        <>
            <h1>Body</h1>
            <h2>{number % 2 === 0 ? "짝수" : "홀수"}</h2>
            <h2>{hello}</h2>
            <h2>{obj.a}</h2>
            <h2>{func()}</h2>
            <h2>{if ...}</h2>
        </>
    )

jsx에서 삼항 연산자를 사용할 수 있다는 것을 알 수 있었다. 삼항 연산자의 결과에는 html tag들도 넣을 수 있는데, 이를 통해서 렌더링하는 방법을 조건부 렌더링이라고 한다.

function Body() {
    const user = {
        name: "name",
        isLogin: false,
    }

    return (
        <div>
            {user.isLogin ? 
                (<div>마이페이지, 로그아웃</div>) : (<div>로그인</div>)
            }
        </div>
    )
}

export default Body

위와 같이 조건부 렌더링을 통해서 isLogin이 참이라면 <div>마이페이지, 로그아웃</div>을 반환하면 아니라면 <div>로그인</div>을 반환한다.

jsx로 만든 요소들에 style을 넣어주는 방법에 대해서 알아보도록 하자.

function Body() {
    const user = {
        name: "name",
        isLogin: false,
    }

    return (
        <div style={{ backgroundColor: "green"}}>
            <h1>Body</h1>
        </div>
    )
}

export default Body

주의할 것은 style에 괄호를 두 번 써주어야 한다는 것과, css처럼 background-color가 아니라 backgroundColor와 같이 두번재 단어부터는 소문자를 넣어주는 방법으로 써주어야 한다.

그런데 보통 이렇게 style을 넣어주지 않고 css파일을 따로 만들어준다.

  • components/Body.css
.body {
    background-color: red;
    border-bottom: 5px solid blue
}

이제 Body.js에서 Body.css 파일을 import해야한다.

  • components/Body.js
import "./Body.css"

function Body() {
    return (
        <div className="body">
            <h1>Body</h1>
        </div>
    )
}

export default Body

html tag에 class를 붙여줄 때는 className을 써준다. 이는 html tag자체에서 class로 쓰는 것과 약간 다른데, 왜냐하면 class자체가 이미 js에서 예약어로 쓰이고 있기 때문이다.

Props

react의 component들은 부모-자식 구조를 가진다고 했는데, 부모 component가 자식 component에게 data를 전달하고 싶을 때는 어떻게해야할까?? 이를 위해서 사용하는 것이 바로 props이다.

먼저 Button component를 만들어보도록 하자.

  • components/Button.jsx
export default function Button() {
    return <button>클릭</button>
}

이제 Body.jsx에서 불러와보도록 하자.

import "./Body.css"
import Button from "./Button"

function Body() {
    return (
        <div className="body">
            <h1>Body</h1>
            <Button/>
            <Button/>
            <Button/>
        </div>
    )
}

export default Body

다음으로 Button.css파일을 만들어 button을 꾸며주도록 하자.

  • components/Button.css
.button {
    padding: 10px 20px;
    font-weight: bold;
    border-radius: 10px;
}

다음으로 Button.jsxbutton.css를 반영해보도록 하자.

import './Button.css'

export default function Button() {
    return <button className="button">클릭</button>
}

이제 모양이 같은 Button 3개가 나올 것이다. 문제는 이 Button이 서로 다른 글을 가졌으면 좋겠다. 이 때 사용하는 것이 바로 props라는 것이다. 바로 부모 component가 자식 component에게 인자를 전달하는 것이다.

  • components/Body.jsx
import "./Body.css"
import Button from "./Button"

function Body() {
    return (
        <div className="body">
            <h1>Body</h1>
            <Button text={"1번 버튼"}/>
            <Button text={"2번 버튼"}/>
            <Button text={"3번 버튼"}/>
        </div>
    )
}

export default Body

text라는 임의의 key값으로 각 Button의 text가 될 data를 넣어주었다. 이것이 바로 props이다. 이제 child component인 Button에서 key인 text를 가진 props를 가져와 쓰면 된다.

  • components/Button.jsx
import './Button.css'

export default function Button(props) {
    console.log(props)
    return <button className="button">클릭</button>
}

props라는 object안에 text라는 key값으로 부모 component에서 전달한 data를 볼 수 있을 것이다. 이제 props를 사용하여 button의 text를 렌더링해보도록 하자.

  • components/Button.jsx
import './Button.css'

export default function Button(props) {
    console.log(props)
    return <button className="button">{props.text}</button>
}

서로 다른 text값을 가진 Button component들을 볼 수 있을 것이다. 추가적으로 color라는 props를 받아와 button의 색깔을 다르게 해주도록 하자.

  • components/Body.jsx
import "./Body.css"
import Button from "./Button"

function Body() {
    return (
        <div className="body">
            <h1>Body</h1>
            <Button text={"1번 버튼"} color={"red"}/>
            <Button text={"2번 버튼"}/>
            <Button text={"3번 버튼"}/>
        </div>
    )
}

export default Body

'1번 버튼'에만 color라는 props를 전달한 것을 볼 수 있다. 이를 style을 통해 적용시켜보도록 하자.

  • components/Button.jsx
import './Button.css'

export default function Button(props) {
    console.log(props)
    return <button className="button" style={{backgroundColor: props.color}}>{props.text}</button>
}

'1번 버튼'만 다른 색깔로 나오는 것을 확인할 수 있을 것이다.

js문법인 구조분해 할당을 통해서 props들의 property들을 가져올 수도 있다.

  • components/Button.jsx
import './Button.css'

export default function Button({text, color}) {
    return <button className="button" style={{backgroundColor: color}}>{text}</button>
}

또한 props를 보내주는 parent component에서도 props를 간단하게 보내주는 방법이 있다.

  • components/Body.jsx
import "./Body.css"
import Button from "./Button"

function Body() {

    const buttonProps = {
        text: "1번 버튼",
        color: "red",
        a: 1,
        b: 2,
        c: 3
    }

    return (
        <div className="body">
            <h1>Body</h1>
            <Button {...buttonProps}/>
            <Button text={"2번 버튼"}/>
            <Button text={"3번 버튼"}/>
        </div>
    )
}

export default Body

사실 별것 없다. buttonProps라는 object의 property들을 spread문법으로 풀어주는 것이다. 어차피 react component들도 실상은 js object이므로 text, color와 같은 key값이 그대로 들어가는 것이다.

props뿐만 아니라 html tag들도 전달해줄 수 있는데, 이 경우에는 사용 방법이 약간 다르다.

  • components/Body.jsx
import "./Body.css"
import Button from "./Button"

function Body() {
    const buttonProps = {
        text: "1번 버튼",
        color: "red",
        a: 1,
        b: 2,
        c: 3
    }
    return (
        <div className="body">
            <h1>Body</h1>
            <Button {...buttonProps}>
                <div>버튼</div>
            </Button>
            <Button text={"2번 버튼"}/>
            <Button text={"3번 버튼"}/>
        </div>
    )
}

export default Body

첫 번째 button의 child button으로 <div>버튼</div>을 넣어준 것을 볼 수 있다. 이제 이 child tag를 Button component에서 어떻게 사용할 수 있는 지 보도록 하자.

  • components/Button.jsx
import './Button.css'

export default function Button({text, color, children}) {
    return (
        <button className="button" style={{backgroundColor: color}}>
            {children}
        </button>
    ) 
}

Body에서 child로 전달한 html tag는 Button에서 children이라는 key값을 통해서 접근이 가능하다. 이를 rendering시켜주기 위해서는 {children}을 사용하면 된다.

children에는 html tag 요소 뿐만 아니라 react component들도 넣을 수 있는데, 다음과 같다.

  • components/Body.jsx
import "./Body.css"
import Button from "./Button"

function ButtonChild() {
    return <div>BUTTON CHILD</div>
}

function Body() {
    const buttonProps = {
        text: "1번 버튼",
        color: "red",
        a: 1,
        b: 2,
        c: 3
    }
    return (
        <div className="body">
            <h1>Body</h1>
            <Button {...buttonProps}>
                <ButtonChild/>
            </Button>
            <Button text={"2번 버튼"}/>
            <Button text={"3번 버튼"}/>
        </div>
    )
}

export default Body

ButtonChild component를 Button component에 넣어주면 Button component의 children props에 주입된다.

0개의 댓글