⦁reactApp설치
https://velog.io/@sago_mungcci/2023.09.09React-App-%EC%84%A4%EC%B9%98
리액트 앱을 설치해서 본격적인 리액트 다루는 법을 배우기 시작함.
index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
//import App from './App'
//import AppEffect from './AppEffect'
//import AppDeps from './AppDeps'
import AppCleanUp from './AppCleanUp'
//import './styles.css'
const root = ReactDOM.createRoot(document.getElementById('root'))
//root.render(<React.StrictMode>{/* <App /> */ <AppEffect />}</React.StrictMode>)
//root.render(<AppEffect />)
//root.render(<AppDeps />)
root.render(<AppCleanUp />)
import Button from './Button'
// npm i prop-types 설치하기
function App() {
return (
<div>
<h1>Welcome Back!</h1>
<Button text={'continue'}></Button>
</div>
)
}
export default App
import PropTypes from 'prop-types'
import styles from './Button.module.css'
import title from './title.module.css'
function Button({ text }) {
return (
// 이렇게 할 필요 없이 위에 임포트 하면 된다.
// <button style={{ backgroundColor: 'tomato', color: 'white' }}>
// {text}
// </button>
<div>
<h1 className={title.title}>Welcome Back!</h1>
<button className={styles.btn}>{text}</button>
</div>
)
}
Button.propTypes = {
text: PropTypes.string.isRequired,
}
export default Button
import { useState, useEffect } from 'react'
// npm i prop-types 설치하기
function AppEffect() {
const [counter, setValue] = useState(0)
const onClick = () => {
setValue((prev) => prev + 1)
}
// rendering이 두번되는 현상이 있어서 찾아보았더니 index.js에
// React.StrictMode 테그에 감싸져 있어서 그렇다고 합니다.
// StrictMode는 create-react-app로 설치했을 때 기본적으로 생성되는 테그로,
// 해당 테그로 감싸져 있는 경우 자손까지 검사한다해서 두 번 실행된다고 합니다.
// React.StrictMode 테그를 지우시고 해보세요.
// 오류 : Error handling response: TypeError: Cannot read properties of undefined (reading 'always')
// ==> 드래그프리때문
// 1. 지금 아래와 같이 처음에 api를 호출하고 또 state가 변경될 때 또 호출하게 된다.
// 처음 들어왔을때 한번만 실행 시키고 state값이 변경되도 호출하지 않게하고 싶다.
console.log('i run all the time')
// const iRunOnlyOnce = () => {
// console.log('i run only once')
// }
// React.useEffect() --> 첫번째 매개변수는 처음 한번만 실행시키고 싶은 코드, 두번째는 deps 추후 설명
//useEffect(iRunOnlyOnce, [])
useEffect(() => {
console.log('i run only once')
}, [])
return (
<div>
<h1>AppEffect{counter}</h1>
<button onClick={onClick}>Click me!</button>
</div>
)
}
export default AppEffect
import { useState, useEffect } from 'react'
// npm i prop-types 설치하기
function AppDeps() {
const [counter, setValue] = useState(0)
const [keyword, setKeyword] = useState('')
const onClick = () => {
setValue((prev) => prev + 1)
}
const onChange = (event) => {
setKeyword(event.target.value)
}
// 일반문장
//console.log('i run all the time')
// 일반문장에 useEffect를 씌웠다고 생각!
useEffect(() => {
console.log('i run only once')
}, [])
// 서칭시 (onChange)에도 아래 return부분이 리렌더링 되면서 함수를 실행시키고
// 클릭할때도 마찬가지로 return부분이 리렌더링 되면서 함수를 실행시킨다.
// 불필요 한 작동을 계속하고 있다.
// 따라서 서칭시에는 onChange이벤트만 실행시키고
// 클릭시에는 onClick이벤트만 실행시키고 싶다.
//console.log('Search for', keyword)
// deps : 저 배열문안에 있는 변수가 변할때만 실행시킨다.(keyword는 검색문)
// 지금 여기서는 if문을 주어서 변수의 값이 변할 때 조건에 따라서 실행시킨다.
useEffect(() => {
// if (keyword !== '' && keyword.length > 5) {
// console.log('Search for', keyword)
// }
console.log('i run when keyword change', keyword)
}, [keyword])
useEffect(() => {
console.log('i run when counter change', counter)
}, [counter])
// keyword나 counter 둘중에 하나의 값만 바뀌어도 실행됨
useEffect(() => {
console.log('i run when keyword&counter change', counter)
}, [keyword, counter])
return (
<div>
<h1>AppEffect</h1>
<input
type="text"
placeholder="Seacrch Here"
onChange={onChange}
value={keyword}
></input>
<h3>{counter}</h3>
<button onClick={onClick}>Click me!</button>
</div>
)
}
export default AppDeps
import { useState, useEffect } from 'react'
// showing이 참일때
// im here이 hello() 컴포넌트에서 실행되고 콘솔에 찍히고 있다.
// showing이 거짓일때
// im here이 hello() 컴포넌트에서 destroy되면서 없어진다.(삭제된다.)
// ** 참고
// useEffect(() => something(), [변수A]) 라고하면, 변수A가 변경될 떄 마다 useEffect는 실행된다. 변수A가 변경되면,
// 이전의 변수A 값을 가지고 return 함수가 실행된다.
// ex) 변수A =1 ->2 변경되는 시점에서 , useEffect()에서 return 외에는 변수A는 2이고, return 상황에서는 변수A는 1이다.
// 뒤에 [ dependency ]에 아무것도 없다면( ex) [] ) 첫 렌더링시에 실행되고, return은 컴포넌트 unmount시(영상의 destroy시) 실행된다.
// 부모 컴포넌트 위에 자식컴포넌트가 있듯이 AppCleanUp 컴포넌트위에 Hello 컴포넌트가 쌓였고 이 쌓인 컴포넌트가 destroy될대 return값을 반환한다.
function Hello() {
// function byeFn() {
// console.log('bye')
// }
// function hiFn() {
// console.log('hi')
// return byeFn
// }
// useEffect(hiFn, [])
// 위 주석친 3문장이 아래의 useEffect와 같다
useEffect(() => {
console.log('im here')
return () => console.log('im destroy') //destroy되면서 실행되는 구문
}, [])
return <h1>Hello</h1>
}
// npm i prop-types 설치하기
function AppCleanUp() {
const [showing, setShowing] = useState(false)
const onClick = () => {
setShowing((prev) => !prev)
}
return (
<div>
{showing ? <Hello /> : null}
<button onClick={onClick}>{showing ? 'Hide' : 'Show'}</button>
</div>
)
}
export default AppCleanUp
useEffect(() => {
console.log('im here')
return () => console.log('im destroy') //destroy되면서 실행되는 구문
}, [])
return <h1>Hello</h1>
return () => console.log('im destroy') //destroy되면서 실행
이부분이 이해가 잘안갔는데,
자바에서는 일반적으로 메서드가 호출되어 실행될때 return문까지 실행되기때문에 굉장히 헷갈렸다.
정확히 이해하려면 2가지를 이해해야 하는데, useEffect()이고 하나는 component인것 같다.
컴포넌트가 부모 컴포넌트위에 자식 컴포넌트가 쌓이면 그 자식 컴포넌트 내부에 있는 함수가 실행된다.
실행하면서 useEffect()에서는 특이한점이 있는데,
useEffect()내부에 있는 코드를 한번만 실행되는 동시에 return문에 있는 함수는 반환을 하지 않는다. 그러나 해당 "컴포넌트"가 destroy함과 동시에 useEffect에있는 return문을 반환하는 것이다.
컴포넌트도 함수로 작동되기 때문에 굉장히 헷갈렸다.