TIL. React Hooks_useEffect

chloeee·2021년 3월 22일
0

TIL

목록 보기
61/81
post-thumbnail

useEffect after render

useEffect는 함수형 컴포넌트에서 side effect 처리를 위해 사용된다. 그리고 class형 컴포넌트의 componentdidmount, componentdidupdate와 같은 역할을 함수형 컴포넌트에서 해준다.

클래스형 컴포넌트

import React,{component} from 'react'

class ClassCounterOne extends Component{
  constructor(props){
    super(props)
    this.state={
      count:0
    }
  }
  
  componentDidMount(){
    document.title=`Clicked ${this.state.count} times`
  }
   componentDidUpdate(prevProps,prevState){
    document.title=`Clicked ${this.state.count} times`
  }
  render(){
    return(
      <div>
      <button onClick={()=>this.setState({count:this.state.count +1})}>
      Click{this.state.count}times
      </button>
      </div>
      )
}
}
export default ClassCounterOne    
    

함수형 컴포넌트

import React,{useState} from 'react'

function HookCounterOne(){
  const [count,setCount]=useState(0)
  
  useEffect(()=>{
    document.title=`you clicked ${count} times`
  })
  
  return(
    <div>
      <button onClick={()=>setCount(count+1)}> Click {count} times </button>
    </div>
      )
}
export default HookCounterOne

useEffect는 컴포넌트 모든렌더 후에 실행된다! 첫번째 렌더 후 그리고 모든 업데이트 후에 실행되는 것이 useEffect

Conditionally run effects

import React, {useState,useEffect} from 'react'

function HookCounterOne(){
  const [count,setCount]=useState(0)
  const [name,setName]=useState('')
  
  useEffect(()=>{
    console.log(`useEffect- updating document title`)
    document.title=`you clicked ${count} times`
  },[count])
  
  return(
    <div>
     <input type="text" value={name} onChange={e=>setName(e.target.value)}/>
     <button onClick={()=>setCount(count+1)} Click {count} times </button>
    </div>
   )
}
export default HookCounterOne

여기서 조건적으로 count value가 바뀔 때만 useEffect가 실행되게 어떻게 할 수 있을까?
=>useEffect에 [count]배열을 넣어주자!

Run effects only once

useEffect는 dependency를 명시해주지 않으면 항상 모든 렌더 후에 호출된다

import React, {useState,useEffect} from 'react'

function HookMouse(){
  const [x,setX]= useState(0)
  const [y,setY]= useState(0)
  
  const logMousePosition =e=>{
    console.log('mouse event')
    setX(e.clientX)
    setY(e.clientY)
  }
  useEffect(()=>{
    console.log('useEffect called')
    window.addEventListener('mousemove', logMousePosition)
  },[])
  return()
}
export default HookMouse

처음 render시에만 useEffect실행되고 그 다음부터는 re-render 안되게 어떻게 할 수 있을까?
useEffect 2번째 parameter에 빈배열[]을 넣어주면 된다!

useEffect with cleanup

import React, {useState} from 'react'
import HookMouse from `./HookMouse`

function MouseContainer(){
  const [display,setDisplay]= useState(true)
  return(
    <div>
     <button onClick={()=>setDisplay(!display)}> Toggle display </button>
{display && <HookMouse/>}// toggle 기능
</div>
 )
}
export default MouseContainer

이벤트 리스너를 제거하고 싶다면?

useEffect(()=>{
  console.log(`useEffect called`)
  window.addEventListener('mousemove',logMousePosition)
  
  return ()=>{
    console.log('Component unmounting code')
    window.removeEventListener('mousemove',logMousePosition)
  }
},[])

useEffect안에서 return으로 removeEventListener를 작성하면 된다.

useEffect with incorrect dependency

import React, {useState, useEffect} from 'react'

function IntervalHookCounter(){
  const [count,setCount]=useState(0)
  
  const tick=()=>{
    setCount(prevCount=>prevCount+1)
  }

  
  useEffect(()=>{
   function doSomething(){
    console.log(someProp)
  }
    doSomething()
    const interval=setInterval(tick,1000)
    return()=>{
      clearInterval(interval)
    }
  },[someProp])
  
  return(
    <div>
    {count}
    </div>
    )
}
export default IntervalHookCounter

useEffect안에서 함수를 호출할 때, 함수를 useEffect안에서 작성해주자. dependency로 명시된 prop을 배열 안에 넣어준다.

빈 의존성 배열은 useEffect가 한번 실행된다는 것을 의미한다. 이 말은 즉 결과적으로 setInterval이 한번 생성된다는 것이다. 그럼 setInterval 콜백은 한번만 실행되기에 setCount(count+1)은 업데이트될 수 없다.
클로져로 인해 count는 항상 0이다. 그러면 timer는 항상 1을 보여줄 것이다. 그러므로 prevState=>prevState+1을 사용해서 count value 클로저 사용을 피해야 한다.

Fetching data with useEffect

import React,{useState,useEffect} from 'react'
import axios from 'axios'

function DataFetching(){
  const [posts,setPosts]=useState({})
  const [id,setId] =useState(1)
  const [idFromButtonClick,setIdFromButtonClick]=useState(1)
  
  const handleClick=()=>{
    setIdFromButtonClick(id)
  }
  
  useEffect(()=>{
    axios
      .get('https://jsonplaceholder.typicode.com/posts/${id}')
      .then(res=>{
       console.log(res)
      setPosts(res.data)
    })
    .catch(err =>{
      console.log(err)
    })
    },[idFromButtonClick])
  
  의존성 배열[]을 넣어줘야 data fetch가 1번만 이루어진다.
  idFromButtonClick을 배열 안에 넣어주면 버튼클릭할 때마다 fetching data가 되는 것이다
  
    return (
      <div>
      <input type="text" value={id} onChange={e=>setId(e.target.value)}/>
<button type="button" onClick={handleClick}> Fetch Post </button>
<div> {post.title}</div>
      // <ul>
      //{ posts.map (post => <li key={post.id}> {post.title}</li>)
      // </ul>
      </div>
      )
}
export default DataFetching
profile
Front-end Developer 👩🏻‍💻

0개의 댓글