React 클라이언트 Ajax 요청

jeongjwon·2023년 3월 30일
0

SEB FE

목록 보기
31/56

📌 React 데이터 흐름

✅ 데이터는 위에서 아래로 하향식(Top Down)으로 흐른다.(단방향식) 그래야 부모 컨포넌트에서 자식 컴포넌트로 전달할 수 있다.

✅ 앱을 만들 때는 상향식(Bottom Up)으로 작은 컴포넌트들부터 큰 컴포넌트로 만들고 테스트를 작성하면 개발하기 더 쉽다.

State 끌어올리기 (Lifting State Up)

부모 컨포넌트의 state 상태 갱신 함수 자체를 하위 컴포넌트에 전달하고, 하위 컴포넌트가 이 함수를 실행한다.

function ParentComponent(){
  const [value, setValue] = useState("");
  const handleChangeValue = () => {
    setValue("새로운 값");
  };
  
  return(
    <div>
    	<div>값은 {value}입니다</div>
  		<ChildComponenet handleChagneValue={handleChangeValue}/>
    </div>
  );
}

function ChildComponent({handleChangeValue}){
  const handleClick = () => {
  	handleChangeValue();
  }
  return(
 	<button onClick={handleClick}>값 변경</button> 
  );
}



📌 Effect Hook

Side Effect

✅ 함수 내 어떤 구현이 함수 외부에 영향을 끼치는 경우 해당 함수에 Side Effect 부수 효과가 있다고 한다.

Pure Function

✅ 순수함수. 오직 함수의 입력만이 함수의 결과에 영향을 주는 함수. 함수의 입력이 아닌 다른 값이 함수의 결과에 영향을 미치면 순수함수가 아니다. 또한 순수함수는 입력으로 전달된 값을 수정하지 않고 항상 동일한 기능을 하기 때문에 예측 가능한 함수이다.
* 따라서 Math.random() 같은 메서드는 동일한 입력에도 불구하고 다른 출력이 나올 수가 있어서 순수함수가 아니다.

function SingleTweet({ writer, body, createdAt }) {
  return <div>
    <div>{writer}</div>
    <div>{createdAt}</div>
    <div>{body}</div>
  </div>
}

React 컴포넌트 SingleTweet 에서 writer, body, createdAt 은 부모 컴포넌트로부터 받아온 props 가 입력으로 JSX Element 가 출력으로 나간다. 이때 , 어떠한 Side Effect 없고 순수함수로 작동한다.

Reac 컴포넌트 내에서 Side Effect 가 생길 수 있는 경우는
fetch 를 사용해 API 정보를 가져오거나 이벤트를 활용해 DOM을 직접 조작할 때의 경우, 타이머를 사용하기 위해 setTimeout 를 하는 경우가 있다.

useEffect

✅ 컴포넌트 내에서 Side Effect 를 실행할 수 있게 하는 Hook.

useEffect(()=>{
	//... 콜백함수
});

첫번째 인자는 함수. 해당 함수 내에서 side effect를 실행.
default 상태로 항상 렌더링할 때마다 실행됨.

useEffect(() => {
	//... 콜백함수
},[종속성1, 종속성2, ...]);

두번째 인자는 dependency array 배열. 어떤 값의 변경이 일어날 때를 의미.
[] 빈배열을 인자로 받을 때, 첫 렌더링 시에만 실행됨.


두 가지의 side effect 가 존재한다.

  1. 정리 clean-up 를 이용하지 않는 effects
  • 매번 새롭게 컴포넌트가 렌더링 될 때 실행.
    • 컴포넌트 생성 후 처음 화면에 렌더링할 경우
    • 컴포넌트에 새로운 props 가 전달되어 렌더링할 경우
    • 컴포넌트에 상태 state 가 바뀌며 렌더링할 경우
function App(){
  const [count, setCount] = useState(1);
  const [name, setName] = useState("");
  
  const handleCountUpdate = () =>{
    setCount(count+1);
  }
  
  const handleInputChange = (e) => {
    setName(e.target.value);
  }
  
  //렌더링마다 매번 실행됨 
  useEffect(() => {
    console.log("렌더링 🎨");
  });
  
  //mount + count 가 변화할 때마다 실행됨
  useEffect(() => {
    console.log("count 변화");
  }, [count]);
  
  //mount + name 가 변화할 때마다 실행됨
  useEffect(() => {
    console.log("name 변화");
  }, [name]);
  
  //mount 될 때만 실행됨
  useEffect(() => {
	console.log("마운트 ⛰️");
  }, []);
  
  
  return(
  	<div>
    	<button onClick={handleCountUpdate}>Update</button>
    	<span>count:{count}</span>
		<input type="text" value={name} onChange={handleInputChange}/>
        <span>name:{name}</span>
    </div>
  )
}
  1. 정리 clean-up 를 이용하는 effects
  • 메모리 누수가 발생하지 않도록 하는 것
function App(){
	const [showTimer, setShowTimer] = useState(false);
  
  	return(
    	<div>
      		{ showTimer && <Timer /> }
      		<button onClick={() => setShowTimer(!showTimer)}>Toggle Button</button>
      	</div>
    )
}


const Timer = (props) => {
	useEffect(() => {
    	const timer = setInterval(() => {
        	console.log("타이머 돌아가는 중... ⏱️");
        },1000);
      
      	//clean-up 시 꼭 필요한 return
      	return () => {
        	clearInterval(timer);
        }
        
    },[]);
  
  	return(
    	<div>
      		<span>타이머를 시작합니다.</span>
      	</div>
    );
}

1과 같이 clean-up이 필요하지 않은 effects 처럼 코드를 작성하면 함수의 구현이 끝났는데도 불구하고 쓸데없이 메모리 누수가 발생한다.


return 을 꼭 작성해줌에 따라 정리 clean-up 가 되었음을 알 수 있다.

Data Fetching -> AJAX 요청

  1. 컴포넌트 내에서 필터링: 전체 목록 데이터를 불러오고, 목록을 검색어로 filter 하는 방법
  2. 컴포넌트 외부에서 필터링: 컴포넌트 외부로 API 요청을 할 때, 필터링 한 결과를 받아오는 방법 (보통, 서버에 매번 검색어와 함께 요청하는 경우가 이에 해당합니다)

서버를 임의로 구현한 stprageUtil.js 대신 진짜 서버였다면,

컴포넌트 내에서 필터링컴포넌트 외부에서 필터링
HTTP 요청의 빈도를 줄일 수 있다. / 브라우저(클라이언트)의 메모리 상에 많은 데이터를 갖게 되므로, 클라이언트의 부담이 늘어난다.클라이언트가 필터링 구현을 생각하지 않아도 된다. / 빈번한 HTTP 요청이 일어나게 되며, 서버가 필터링을 처리하므로 서버가 부담을 가져간다.

➡️ 진짜 서버라면, ```fetch API``` 를 이용하여 서버에 요청해보자!
useEffect(() => {
	fetch(`http://서버주소/proverbs?q=${filter}`);
  		.then(resp => resp.json())
  		.then(result => {
          setProberbs(result);
        });
},[filter]);

API읜 엔드포인트를 getProberbs 함수 대신 query parameter 를 이용하여 응답을 받아와 state 상태 갱신을 해준다.

➡️ 모든 네트워크의 응답이 즉각적인 것은 아니기 때문에, 외부 API 접속이 느릴 경우를 대비하여 로딩 화면(loading indicator)의 구현이 필수적이다.

const [isLoading, setIsLoading] = useState(ture); //상태처리

return {isLoading ? <LoadingIndicator /> : <div>로딩 완료 화면</div>}
        //true 일 경우에만 loading indicator 설정
        
//useEffect 새롭게 작성시
useEffect(() => {
  	setIsLoading(true); // 
	fetch(`http://서버주소/proverbs?q=${filter}`)
  		.then(resp => resp.json())
  		.then(result => {
      		setProverbs(result);
      		setIsLoading(false);//
    	});
},[filter]);

fetch 요청 전후로 setIsLoading을 설정해주면 보다 간편하고 효율적으로 UX 을 구현할 수 있다.

0개의 댓글