패스트캠퍼스 프론트엔드 8주 완성 with React 학습일지 8주차

이소연·2022년 9월 27일
0
post-thumbnail

이 번 강의를 통해서 20가지 이상의 라이브러리를 사용해 본다고 한다.
무엇보다 새로운 것을 익히는데 있어서 두려움을 없애고,
혼자 할 수 있는 힘을 기르는 것이 이번 강의의 목표라고 하셨다.
공식 문서를 기본으로 내용을 익히면서
공식 문서 안에서 반복적인 패턴을 찾아 새로운 기술을 익히는 요령을 습득하는 것이 목표다.

리액트의 장점

  • 리액트를 사용하는 사용자가 많아서 모르는 부분을 물어볼 수 있는 곳이 많다.
    대표적으로 stackover flow, 구글링..
  • 관련된 라이브러리가 많다.
  • 나와 같은 고민을 했던 사람이 많다..
  • 실무에서 사용할 확률이 높다.

리액트와 관련된 라이브러리

모션 : https://www.framer.com/docs/examples/

상태 매니징, 데이터 패칭 : https://swr.vercel.app/ko/docs/getting-started


React 1.

React 1-1. DOM

Document Object Model : 문서를 논리 트리로 표현한다.

React 1-2. 바닐라 자바스크립트

라이브러리나 프레임워크를 사용하지 않은 순수한 자바스크립트

React 1-3. sand box

프론트엔드 코드 sandBox ↓

https://codesandbox.io/s/

React 1-4. JSX, Babel

const rootEl = document.getElementById('root');

const h1El = React.createElement(
	'h1', 
	{
	  className: 'title',
	  children: ['Hello world!!!!', "It's me"]
	},
	['Hello world!!!!', "It's me"]
);
console.log(h1El);

ReactDOM.render(h1El, rootEl);

JSX : 문자도 HTML도 아닌 JavaScript의 확장 문법

// JSX
const element = <h1>Hello, world!</h1>; // 이 문법은 자바스크립트에서 이해할 수 없다

JSX의 문법을 Javascript도 이해할 수 있도록
Javascript 문법으로 바꾸기 위해 Babel을 이용할 수 있다.

Babel : Javascript Complier
https://babeljs.io/docs/en/babel-standalone

React 1-5. multi element 생성하기

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- react cdn -->
  <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

  <!-- babel cdn -->
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

</head>
<body>
    <div id="root"></div>

    <script type="text/babel">
      const rootEl = document.getElementById('root');

      const paint = (title, desc) => {
        <>
          <h1>{title}</h1>
          <h3>{desc}</h3>
        </>
      }

      const Paint = ({title, desc, children}) => {
        return(
          <>
            <h1>{title}</h1>
            <h3>{desc}</h3>
            {children}
          </>
        )
      }

      // const element = (
      //   <>
      //     <Paint title="good" desc="hi">
      //       <span>hello</span>
      //     </Paint>
      //     <Paint title="so good" desc="hi" />
      //     <Paint title="so so good" desc="hi" />
      //   </>
      // )

      const Good = () => <h3>ohohoh</h3>

      const element = (
        <>
          <Paint title="Good" desc="good">
            <Good />
            <Good />
            <Good />
          </Paint>
        </>
      )

      ReactDOM.render(element, rootEl)
    </script>
</body>
</html>

경고 중에

You are using the in-browser Babel transformer. Be sure to precompile your scripts for production

production에서는 이렇게 하지 마라. 미리 컴파일 해 놓아라

지금은 babel을 cdn주소로 직접 넣어 쓰는데 보통 제품을 만들 때는 이렇게 쓰지 않고
패키징을 하면서 babel로 컴파일링 까지 한 내용을 사용자에게 제공한다.
지금은 예시로 진행 중이라 무시해도 되는 경고이다.

React 2. 리렌더링

리렌더링은 React의 큰 장점이다.
Vanila Javascript 에서는 변경으로 인해 element를 다시 그리고,
React 에서는 변경된 부분만 다시 그린다.

React 3. 이벤트 핸들러

리액트에서는 인라인으로 함수를 넣는 것을 권장하고 camelCase 방식으로 이벤트를 불러온다.

React 3-1. 간단한 검색창 만들어보기

<div id="root"></div>

<script type="text/babel">
	const rootElement = document.getElementById('root')
  const state = {keyword: '', typing: false, result: ''}

  const App = () => {
    function handleChange (event) {
      setState({keyword: event.target.value}) 
    }
    // return 으로 전달되는 값은 불변객체
    return (
      <>  
        <input onChange={handleChange} />
        <button>search</button>
        <p>Looking for {state.keyword}...</p>
      </>
    )
  }

  function setState(newState) {
    Object.assign(state, newState)
  }

  // 불변객체를 한 번 렌더링 하고 나면 다시 그려주지 않기 때문에 input창에 작성해도(value 값이 전달되도) 아무것도 바뀌지 않는다.
  ReactDOM.render(<App />, rootElement)
</script>

위 코드에서 문제는 App에서 return되는 값은 불변 객체이다.

ReactDOM.render(, rootElement) 로 한 번 렌더링 하고 나면 다시 그려주지 않기 때문에

input창에 텍스트를 입력해도 (value값이 전달 돼도) p태그의 내용이 변하지 않는다.

React 4. useState Hook으로 컴포넌트 상태 다루기

Hook : React 에서 use로 시작하는 어떤것…
DOM : 논리 트리
component : element의 집합
element : 요소, component의 구성요소

리액트에서 작성한 로직에서 컴포넌트의 변화가 다양할 때 어떻게 해야하나..
필요할 때 마다 전역변수를 생성하지 않고, useState 를 사용한다.

<div id="root"></div>

    <script type="text/babel">
      const rootElement = document.getElementById('root')

      function setState(newState) {
        Object.assign(state, newState)
        render()
      }

      const App = () => {
        const [keyword, setKeyword] = React.useState('')

        function handleChange (event) {
          setKeyword(event.target.value)
        }

        function handleClick () {

        }

        return (
          <>  
            <input onChange={handleChange} />
            <button onClick={handleClick}>search</button>
            <p>{`Looking for... ${keyword}`}</p>
          </>
        )
      }

      ReactDOM.render(<App />, rootElement)

    </script>

input요소에 값을 입력하면 렌더를 다시 하지 않아도 p태그에 내용이 변화된다.
React.useState() 함수에 값을 넣어주면 값이 바뀌는 것을 바로 인지하기 때문이다.
인자로는 배열, 객체, 문자, 숫자, boolean 등 모두 올 수 있다.
React.useState()는 배열로 값이 전달 되고
첫 번째 값은 관리할 상태의 값, 두 번째 값은 업데이트 해줄 값이다.

React 5. useEffect Hook으로 컴포넌트 사이드 이펙트 다루기

복습을 할 때 지금 하려는 건

keyword의 값이 바뀔 때 마다 로컬 스토리지에 새롭게 값을 저장하려고 한다.
keyword에 변화가 생길 때 사이드 이펙트로 로컬 스토리지에 저장을 하고 싶다.
사이드 이펙트를 쓰려면 React.useEffect() 함수를 사용하면 된다.
첫 번째 인자는 useEffect가 실행될때마다 실행되는 함수를 넣어주면 되고,
두 번째 인자는 옵션이다. 값을 안넣을 수도 있고 [] 빈배열을 넣을 수도 있는데
어쨌든 두 번째 인자에 들어가는 배열은 의존성 배열이고
의존성 배열 안에 있는 값이 바뀔 때 마다 첫 번째 인자의 함수가 실행된다.
값을 안주면 모든 변화에 무한히 첫 번째 인자 함수가 실행된다. 이렇게는 잘 사용하지 않는다.
[] 빈 배열을 넣으면 처음 렌더링 될때만 실행된다. 즉, 컴포넌트가 처음 동작될 때만 한 번 실행된다.
배열에 어떤 키워드를 넣어주면 그 키워드값이 변할 때만 실행된다.
는 것을 알고 보면 좋을 것 같다…

lazy initialize

즉, 함수의 실행이 끝나고 리턴값을 초기값으로 받아와서 초기화를 조금 더 늦게 할 수 있다.

<div id="root"></div>

<script type="text/babel">
  const rootElement = document.getElementById('root')

  const App = () => {
    const [keyword, setKeyword] = React.useState( () =>  {

      console.log('초기화')
      return window.localStorage.getItem('keyword')

    })
    const [result, setResult] = React.useState('')
    const [typing, setTyping] = React.useState(false)

    console.log('render')

    React.useEffect ( () => {
      console.log('effect')
      window.localStorage.setItem('keyword', keyword)
    } , [keyword])

    function handleChange (event) {
      setKeyword(event.target.value)
      setTyping(true)
    }

    function handleClick () {
      setTyping(false)
      setResult(`we find results of ${keyword}`)
    }

    return (
      <>  
        <input onChange={handleChange} value={keyword} />
        <button onClick={handleClick}>search</button>
        <p>{ typing ?  `Looking for... ${keyword}` : result }</p>
      </>
    )
  }

  ReactDOM.render(<App />, rootElement)

</script>

React 6. 커스텀 훅 만들기

useState, useEffect 가 반복될 때는 커스텀 훅 (함수)를 만들어서 사용할 수 있다.

React 7. Hook Flow

hook flow : 컴포넌트를 실행하고 그 안에서 훅이 언제 호출되고 언제 사라지는지

또 컴포넌트끼리 중첩될 때는 컴포넌트들 간의 훅 호출 타이밍은 어제인지 확인 하는 것

React 7-1. hook의 호출 타이밍

button을 누르면 input이 나타나고 input에 값을 입력하면 p태그에 내용이 입력되도록 해본다.
다시 button을 누르면 input이 사라지게 해본다.

<div id="root"></div>

<script type="text/babel">
  const rootElement = document.getElementById('root')
  
  // show 가 false 즉, 인풋창이 가려질 때는 반응하지 않는다.
  const Child = () => {
    console.log('  Child render start')
    const [text, setText] = React.useState(() => {
      console.log('  Child useState')

      return ''
    })

    React.useEffect(() => { 
      console.log('  Child useEffect: no deps') 

      return () => {
        console.log('  Child useEffect !!CLEANUP!!: no deps')
      }
    })
    React.useEffect(() => { 
      console.log('  Child useEffect: empty array')
      
      return () => {
        console.log('  Child useEffect !!CLEANUP!!: empty array')
      }
    }, [])
    React.useEffect(() => { 
      console.log('  Child useEffect: [text]') 

      return () => {
        console.log('  Child useEffect !!CLEANUP!!: [text]')
      }
    }, [text])

    function handleChange (event) {
      setText(event.target.value)
    }

    const element = (
      <> 
        <input onChange={handleChange} />
        <p>{text}</p> 
      </>
    )

    console.log('  Child render end')

    return element
  }

  const App = () => {
    console.log('app render start')

    const [show, setShow] = React.useState(() => {
      console.log('App useState') // 처음 렌더링 될 때만 반응
      
      return false
    })

    // App의 useEffect는 Child의 useEffect까지 모두 반응하고 나서 반응한다.
    React.useEffect(() => { 
      console.log('App useEffect: no deps') 

      return () => {
        console.log('App useEffect !!CLEANUP!!: no deps')
      }
    }) // 어떤 변화가 일어날 때 마다 반응
    React.useEffect(() => { 
      console.log('App useEffect: empty array') 

      return () => {
        console.log('App useEffect !!CLEANUP!!: empty array')
      }
    }, []) // 처음 레더링 될 때만 반응
    React.useEffect(() => { 
      console.log('App useEffect: [show]') 

      return () => {
        console.log('App useEffect !!CLEANUP!!: [show]')
      }
    }, [show]) // show 키워드가 변화될 때만 반응

    // useState로 만들어진 set..함수는 기본적으로 이전 값이 인자로 들어온다.
    // prev라는 임의의 이름으로 인자를 받으면 그 반대값으로 지정해주면 true 일 때 false, false 일 때 true 값을 반환한다.
    function handleClick () {
      setShow( prev => !prev);
    }

    console.log('app render end')

    return (
      <>
        <button onClick={handleClick}>Search</button>
        {show ? <Child />  : null}
      </>
    )
  }

  console.log('hmm.. first!') // 스크립트 코드는 처음 렌더링 될 때만 반응

  ReactDOM.render(<App />, rootElement) // 리액트 렌더함수는 값이 바뀔 때마다 반응

  console.log('umm..!') // 스크립트 코드는 처음 렌더링 될 때만 반응
</script>

React 8. React element style

지금까지 들었던 리액트 내용을 정리해보았다... 8주차 까지 모두 듣지는 못했다 ㅠ
한 번 밀리면 계속 밀린다 ㅠㅠ 내일까지 하루는 더 남았으니 꼭 100% 채워야겠다..
그리고 리액트는 처음 배워보는거라 처음에는 듣는게 많이 어렵긴했다...
강사님이 계속 반복한다고 하셨었는데
쭉 들어보니 확실히 같은 내용이 많이 반복적으로 강의가 진행되어서 조금씩 듣기가 편해졌다.
이번 기회로 리액트 공부를 시작해볼 수 있어서 만족한다.

#패스트캠퍼스 #내일배움카드 #국비지원 #K디지털기초역량훈련 #바이트디그리 #react강의 #React&Redux로시작하는웹프로그래밍

0개의 댓글