Make Be BackEnd

useRef, useNavigate, useLocation, useRecoilState, useEffect, React.FC 본문

React

useRef, useNavigate, useLocation, useRecoilState, useEffect, React.FC

Initsave 2024. 7. 29. 21:01

useRef

특정 DOM요소에 직접적으로 접근을 할 수 있다. 일반적으로 리액트는 직접적인 접근을 허용하지 않는다. (리액트는 상태(state)와 속성(props)을 통해 UI를 업데이트하고 관리한다.)

DOM요소에 접근 하는 이유 ?

  1. 특정 DOM요소에 접근
  2. 직접적인 DOM조작이 필요한 경우
  3. 비제어 컴포넌트(Uncontrolled Components)
const 변수 = useRef<HTMLInputElement>(null);
/* 
DOM 객체주소가 필요한 상황이 생기는 경우 , useRef를 사용한다.
HTMLInputElement, 표준 HTML 입력 요소를 나타내고, TypeScript의 타입 시스템을 통해 타입 검사를 제공
title 의 값을 null로 초기화 하는 이유는 초기화 시점의 DOM요소가 없기(처음 랜더링 될 때는 해당 요소가 없다) 때문이다.
> 초기화의 필요성
 1. DOM 요소가 아직 존재하지 않음
 2. 타입 안전성
 3. 랜더링 후 업데이트
 
 useRef를 사용한 경우 '.current'를 통해 ref의 객체의 값을 얻을 수 있다.
*/
!title.current?.value || query.push(`searchTitle=${title.current?.value}`);
/*

1. title.current?.value
 title은 useRef를 통해 생성된 참조 객체입니다.
 title.current는 현재 참조하는 DOM 요소를 가리킵니다. 
 예를 들어, <input> 요소를 참조하고 있다면, title.current는 해당 input 요소입니다.
 title.current?.value는 선택적 체이닝(옵셔널 체이닝) 연산자를 사용하여 
 title.current가 존재하는 경우 그 요소의 value 속성에 접근합니다. 
 만약 title.current가 null 또는 undefined일 경우, 
 title.current?.value는 undefined가 됩니다.

2. !title.current?.value
 ! 연산자는 논리 부정을 의미합니다. title.current?.value가 undefined, null, 
 빈 문자열("") 또는 false일 경우, 이 표현식은 true로 평가됩니다.
 따라서, title.current?.value가 존재하지 않거나 빈 값일 때 
 !title.current?.value는 true가 됩니다.

3. || query.push(...)
 || 연산자는 논리 OR 연산자입니다. 왼쪽 표현식이 false일 경우, 오른쪽 표현식을 평가합니다.
 이 코드에서 !title.current?.value가 true일 경우, query.push(...)가 실행됩니다. 
 즉, title.current?.value가 존재하지 않거나 빈 값일 때, query 배열에 
 새로운 쿼리 문자열이 추가됩니다.
 전체 작동 방식
 이 코드의 목적은 title.current?.value가 비어 있거나 존재하지 않을 때, 
 쿼리 배열(query)에 searchTitle 파라미터를 추가하는 것입니다. 
 만약 title.current?.value가 존재하고 비어 있지 않다면, 쿼리 배열에 추가되지 않습니다.
*/

useNavigate

React Router v6에서 제공, 훅은 프로그래밍 방식으로 페이지를 탐색하는 데 사용된다. 이전 버전 React Router에서는 ‘useHistory’를 사용하여 동일하게 작동했다 하지만 v6에서는 ‘useNavigate’로 대체

useNavigate 훅을 사용하면 함수형 컴포넌트 내에서 프로그래밍 방식으로 다른 경로로 이동할 수 있다. 주로 버튼 클릭이나 폼 제출과 같은 이벤트 핸들러 내에서 사용된다.

import React from 'react';
import { useNavigate } from 'react-router-dom';

const HomePage = () => {
  const navigate = useNavigate();

  const handleButtonClick = () => {
    navigate('/about');
  };

  return (
    <div>
      <h1>Home Page</h1>
      <button onClick={handleButtonClick}>Go to About Page</button>
    </div>
  );
};

export default HomePage;

여러가지 사용법

  1. 특정 경로로 이동
  2. navigate('/path');
  3. 경로와 상태 함께 전달
  4. navigate('/path', { state: { from: 'home' } });
  5. 경로 변경 후 다시 탐색 방지
  6. navigate('/path', { replace: true });
  7. 한 단계 앞으로 이동
  8. navigate(1);
  9. 한 단계 뒤로 이동
  10. navigate(-1);
/* 로그인 폼에서 'useNavigate'를 사용해서 로그인 성공 후 대시보드로 이동하는 예제 */
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';

const LoginForm = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const navigate = useNavigate();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    // 여기서 실제 로그인 로직을 수행합니다.
    if (username === 'user' && password === 'password') {
      navigate('/dashboard');
    } else {
      alert('Invalid credentials');
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Username:
          <input
            type="text"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
          />
        </label>
      </div>
      <div>
        <label>
          Password:
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </label>
      </div>
      <button type="submit">Login</button>
    </form>
  );
};

export default LoginForm;

useLocation

현재의 URL 경로, 쿼리 파라미터 및 해시를 포함한 위치 객체를 반환, useLocation을 사용하면 현재 페이지의 경로에 대한 정보를 쉽게 접근하고, 이를 기반으로 컴포넌트를 랜더링하거나 로직을 처리할 수 있다.

  • pathname: 현재 URL의 경로 부분 (예: /home, /products) , 현재 URL 경로
  • search: URL의 쿼리 문자열 부분 (예: ?query=react), 쿼리 문자열
  • hash: URL의 해시 부분 (예: #section1), 해시
  • state: Link 컴포넌트에서 전달된 상태 (있다면), 상태 (있다면)

기본 사용법

import React from 'react';
import { useLocation } from 'react-router-dom';

const LocationDisplay = () => {
  const location = useLocation();

  return (
    <div>
      <p><strong>Current Path:</strong> {location.pathname}</p>
      <p><strong>Query String:</strong> {location.search}</p>
      <p><strong>Hash:</strong> {location.hash}</p>
      <p><strong>State:</strong> {JSON.stringify(location.state)}</p>
    </div>
  );
};

export default LocationDisplay;

쿼리 문자열 처리

import React from 'react';
import { useLocation } from 'react-router-dom';

const QueryDisplay = () => {
  const location = useLocation();
  const queryParams = new URLSearchParams(location.search);
  const searchTerm = queryParams.get('searchTerm');

  return (
    <div>
      <p><strong>Search Term:</strong> {searchTerm}</p>
    </div>
  );
};

export default QueryDisplay;

리디렉션과 조건부 렌더링

import React from 'react';
import { useLocation } from 'react-router-dom';

const ConditionalRender = () => {
  const location = useLocation();

  return (
    <div>
      {location.pathname === '/special-page' && <p>Special page content</p>}
    </div>
  );
};

export default ConditionalRender;

export interface 로 타입을 지정하는 이유는?

TypeScript가 정적 타입 검사를 통해 코드의 안정성과 오류를 줄이기 위해서 이다.

  • 타입 안정성: 타입을 지정함으로써 코드에서 발생할 수 있는 오류를 사전에 방지합니다.
  • 자동 완성 및 문서화: IDE에서 자동 완성 기능과 문서화 기능을 통해 개발 생산성을 향상시킵니다.
  • 가독성 및 유지보수성: 명확한 타입 정의로 코드의 가독성을 높이고 유지보수를 쉽게 합니다.
  • 모듈화 및 재사용성: 공통의 타입 정의를 재사용하여 코드의 일관성을 유지합니다.
  • 동적 타입 검사: 정적 타입 검사를 통해 런타임 오류를 줄이고 안정적인 코드를 작성합니다.

useRecoilState

컴포넌트 상태관리 라이브러리이고, Recoil의 상태를 읽고 업데이트하는 데 사용된다.

  • Atom : Recoil 상태의 기본 단위, 상태 저장, 해당 상태를 읽거나 업데이트 하는 방법 제공
  • /* 상태 정의 */ import { atom } from 'recoil'; export const exampleState = atom({ key: 'exampleState', // 고유한 키 default: '', // 기본 값 }); /* 컴포넌트에서 상태를 읽고 업데이트 */ import React from 'react'; import { useRecoilState } from 'recoil'; import { exampleState } from './atoms'; // atom 파일에서 가져오기 const ExampleComponent: React.FC = () => { const [value, setValue] = useRecoilState(exampleState); const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { setValue(event.target.value); // 상태 업데이트 }; return ( <div> <input type="text" value={value} onChange={handleChange} /> <p>Current Value: {value}</p> </div> ); }; export default ExampleComponent;
  • Selector : Recoil 상태를 기반으로 파생된 상태 계산하는데 사용, 상태를 변형하거나 조합하여 새로운 값을 생성

‘useRecoilState’ 훅은 현재 상태, 상태를 업데이트하는 함수를 반환한다.

useRecoilState vs useRecoilValue vs useSetRecoilState

/* useRecoilValue */
import { useRecoilValue } from 'recoil';
import { exampleState } from './atoms';

const DisplayComponent: React.FC = () => {
  const value = useRecoilValue(exampleState);
  
  return (
    <div>
      <p>Current Value: {value}</p>
    </div>
  );
};

export default DisplayComponent;

/* useSetRecoilState */
import { useSetRecoilState } from 'recoil';
import { exampleState } from './atoms';

const UpdateComponent: React.FC = () => {
  const setValue = useSetRecoilState(exampleState);

  const handleClick = () => {
    setValue('New Value'); // 상태 업데이트
  };

  return (
    <button onClick={handleClick}>Update Value</button>
  );
};

export default UpdateComponent;

useEffect

사이드 이펙트를 관리하기 위해 사용하는 훅, 사이드 이펙트란 컴포넌트의 렌더링과는 직접적으로 관련이 없는 작업을 의미, 예를 들어 데이터 fetching, 구독 설정, DOM 직접 조작 등이 사이드 이펙트에 해당된다.

/* 기본 사용 */
import React, { useState, useEffect } from 'react';

const ExampleComponent = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 이 코드는 컴포넌트가 렌더링된 후 실행됩니다.
    document.title = `Count: ${count}`;

    // cleanup 함수는 컴포넌트가 언마운트되거나
    // 의존성 배열의 값이 변경될 때 실행됩니다.
    return () => {
      document.title = 'React App';
    };
  }, [count]); // count가 변경될 때마다 Effect가 실행됩니다.

  return (

Count: {count}

  );
};

export default ExampleComponent;

/* 의존성 배열 */
// 빈배열
useEffect(() => {
  console.log('Component mounted');

  return () => {
    console.log('Component unmounted');
  };
}, []); // 빈 배열

// 특정 값
useEffect(() => {
  console.log('Value changed:', dependency);

  return () => {
    console.log('Cleanup for value:', dependency);
  };
}, [dependency]); // dependency 값이 변경될 때마다 Effect 실행

// 의존성 배열 생략
useEffect(() => {
  console.log('Component rendered');
});

// Cleanup 함수
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Timer tick');
  }, 1000);

  // Cleanup 함수
  return () => {
    clearInterval(timer);
  };
}, []); // 빈 배열, 컴포넌트가 마운트 될 때만 타이머 설정

/* API에서 데이터 가져오는 예제 */
// 데이터 Fetching
import React, { useState, useEffect } from 'react';
import axios from 'axios';

const DataFetchingComponent = () => {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await axios.get('<https://api.example.com/data>');
        setData(response.data);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, []); // 빈 배열, 컴포넌트가 처음 렌더링될 때만 데이터 fetching

  if (loading) return

Loading...

;
  if (error) return

Error: {error.message}

;

  return (

Data

    {data.map(item => (
  • {item.name}
  • ))}
  );
};

export default DataFetchingComponent;

URLSearchParams란 ?

JavaScript의 내장 객체로 URL의 쿼리 문자열을 쉽게 조작하고 관리할 수 있도록 도와준다, 주로 URL의 쿼리 문자열을 파싱, 생성, 수정하는데 사용

React.FC

TypeScript와 React를 함께 사용할 때, 함수형 컴포넌트(Function Component)를 정의하기 위해 사용되는 타입이다. 이 타입을 사용하면 컴포넌트의 Props를 명확하게 정의하고 타입 안전성을 높일 수 있다.

기본적으로 ‘children’을 포함하는 Props를 제공한다. (java에서 인터페이스와 비슷하다)

/* 기본 사용법 */
import React, { FC } from 'react';

interface MyComponentProps {
  title: string;
  isActive: boolean;
}

const MyComponent: FC<MyComponentProps> = ({ title, isActive }) => {
  return (
    <div>
      <h1>{title}</h1>
      <p>{isActive ? 'Active' : 'Inactive'}</p>
    </div>
  );
};

export default MyComponent;