이 번 강의를 통해서 20가지 이상의 라이브러리를 사용해 본다고 한다.
무엇보다 새로운 것을 익히는데 있어서 두려움을 없애고,
혼자 할 수 있는 힘을 기르는 것이 이번 강의의 목표라고 하셨다.
공식 문서를 기본으로 내용을 익히면서
공식 문서 안에서 반복적인 패턴을 찾아 새로운 기술을 익히는 요령을 습득하는 것이 목표다.
리액트와 관련된 라이브러리
모션 : https://www.framer.com/docs/examples/
상태 매니징, 데이터 패칭 : https://swr.vercel.app/ko/docs/getting-started
Document Object Model : 문서를 논리 트리로 표현한다.
라이브러리나 프레임워크를 사용하지 않은 순수한 자바스크립트
프론트엔드 코드 sandBox ↓
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
<!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의 큰 장점이다.
Vanila Javascript 에서는 변경으로 인해 element를 다시 그리고,
React 에서는 변경된 부분만 다시 그린다.
리액트에서는 인라인으로 함수를 넣는 것을 권장하고 camelCase 방식으로 이벤트를 불러온다.
<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태그의 내용이 변하지 않는다.
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()는 배열로 값이 전달 되고
첫 번째 값은 관리할 상태의 값, 두 번째 값은 업데이트 해줄 값이다.
복습을 할 때 지금 하려는 건
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>
useState, useEffect 가 반복될 때는 커스텀 훅 (함수)를 만들어서 사용할 수 있다.
hook flow : 컴포넌트를 실행하고 그 안에서 훅이 언제 호출되고 언제 사라지는지
또 컴포넌트끼리 중첩될 때는 컴포넌트들 간의 훅 호출 타이밍은 어제인지 확인 하는 것
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>
지금까지 들었던 리액트 내용을 정리해보았다... 8주차 까지 모두 듣지는 못했다 ㅠ
한 번 밀리면 계속 밀린다 ㅠㅠ 내일까지 하루는 더 남았으니 꼭 100% 채워야겠다..
그리고 리액트는 처음 배워보는거라 처음에는 듣는게 많이 어렵긴했다...
강사님이 계속 반복한다고 하셨었는데
쭉 들어보니 확실히 같은 내용이 많이 반복적으로 강의가 진행되어서 조금씩 듣기가 편해졌다.
이번 기회로 리액트 공부를 시작해볼 수 있어서 만족한다.
#패스트캠퍼스 #내일배움카드 #국비지원 #K디지털기초역량훈련 #바이트디그리 #react강의 #React&Redux로시작하는웹프로그래밍