React Native

[TIL] 1218 React,

sihanni 2024. 12. 18. 11:56

아무래도 리액트 지식이 빈약하다보니 채팅 서비스를 만들면서 웹 화면은 GPT의 도움을 많이 받았다.

리팩토링을 진행하면서 지식을 내것으로 만들고자 기록하게 됐다.

애매하게 알던 것도 제대로 알고 넘어가자. 어중간하게 알면서 애매하게 사는건 좋지않다.

 

e.preventDefault();

e.preventDefault()는 이벤트가 발생했을 때, 해당 이벤트가 기본적으로 수행하는 동작을 막는 메서드
예를 들어, 폼 제출 시 페이지가 리로드되는 기본 동작을 막고, 대신 JavaScript로 사용자 정의 동작을 수행하도록 할 수 있다.
e.preventDefault()는 폼을 제출할 때 페이지 리로드 없이 자바스크립트로 데이터를 처리하게 된다.

 

fetch
fetch는 JavaScript에서 HTTP 요청을 보내기 위한 내장 API
fetch는 네트워크 요청을 비동기적으로 처리하며, Promise를 반환하며 요청이 완료된 후 응답을 처리하는 방식으로 동작한다.

 

App.tsx

리액트 애플리케이션의 핵심인 최상위 컴포넌트

애플리케이션의 진입점으로, 구성 요소들을 연결하고 상태 관리와 라우팅을 설정하는 중요한 역할을 한다.

이 파일에서는 애플리케이션 전반에 걸쳐 컴포넌트를 관리하고, 글로벌 상태를 설정하고, 에러 핸들링이나 기타 공통적인 로직을 처리할 수 있다.

 

useEffect(실행할 삼수, 의존성 배열)

React에서 side effect(부수 효과)를 처리하는 가장 중요한 Hook이다.

side effect란 컴포넌트의 렌더링 과정에서 발생하는 렌더링 외의 작업을 의미한다. (Api 호출, 타이머 설정, 이벤트 리스너 등록, 로컬 스토리지 작업 등)

const Example: React.FC = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 컴포넌트가 마운트될 때 실행되는 부수 효과
    console.log('Component mounted or count changed:', count);

    // 클린업 함수 반환 (옵션)
    return () => {
      console.log('Cleanup before component unmount or count change');
    };
  }, [count]);  // count가 변경될 때마다 useEffect가 실행됨

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increase</button>
    </div>
  );
};


import TokenManager from './common/tokenManager';

const App: React.FC = () => {
  useEffect(() => {
    const tokenManager = TokenManager.getInstance();
    tokenManager.startTokenUpdate();
    return () => {};
  }, []);

  return (
    <Router>
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='/signIn' element={<SignIn />} />
        <Route path='/signUp' element={<SignUp />} />

        {/* PrivateRoute로 감싸서 /main 경로에 접근을 인증된 사용자로 제한 */}
        <Route element={<PrivateRoute />}>
          <Route path='/main' element={<MainPage />} />
          <Route path='/profile' element={<ProfilePage />} />
          <Route path='/chat' element={<ChatPage />} />
          <Route path='/chat/:id' element={<ChatPage />} />
        </Route>
      </Routes>
    </Router>
  );
};

export default App;

 

  • 처음 렌더링 시: useEffect의 내용은 렌더링 후에 비동기적으로 실행됩니다. 즉, UI가 먼저 렌더링되고 나서 부수 효과가 발생합니다.
  • 의존성 배열: useEffect의 두 번째 인자로 전달된 의존성 배열에 포함된 값이 변경될 때마다 해당 useEffect가 실행됩니다. 이 배열이 비어 있으면 useEffect는 컴포넌트가 마운트될 때 한 번만 실행됩니다.
  • 클린업: useEffect 내에서 반환된 함수는 컴포넌트가 언마운트될 때 또는 의존성 배열의 값이 변경될 때 호출되어 이전 효과를 정리합니다.
  • app.tsx내에 있는 useEffect는 컴포넌트가 마운트 될 때 한 번만 실행 된다. (두번쨰 배열이 비어있기 떄문에)
    애플리케이션이 실행되면서 자동으로 토큰 갱신 작업이 시작될 수 있는 것이다.

 

 

 

싱글톤 패턴

특정 클래스에 대해 전역적으로 하나의 인스턴스만 생성되도록 보장하는 패턴이다.

주요 목적 : 애플리케이션 전역에서 하나의 인스턴스를 공유하여 해당 인스턴스를 접근해서 사용하며, 보통 자원 관리나 상태 관리가 중요한 경우에 사용된다.

  • 유일한 인스턴스
    클래스의 인스턴스는 오직 하나만 존재해야하며, 이 인스턴스는 애플리케이션 전역에서 공유된다.
  • 인스턴스에 대한 접근
    외부에서는 싱글톤 클래스의 유일한 인스턴스에 접근하기 위한 메서드 호출이 필요하다.
  • 전역 상태 관리 
    애플리케이션 전체에서 접근할 수 있으므로, 상태를 중앙에서 관리할 수 있다.
  • 생성자
    생성자는 private로 선언되어 외부에서 인스턴스를 생성할 수 없도록 한다.
  • 정적 변수
    클래스 내부에 정적 변수를 두어 유일한 인스턴스를 보관한다.

 

static

static은 클래스의 인스턴스가 아닌 클래스 자체에 속하는 속성이나 메서드를 정의하는 데 사용

클래스가 여러 번 생성되더라도 static으로 정의된 속성은 클래스의 모든 인스턴스가 공유하게 됌

클래스 레벨에서 관리되므로

클래스의 하나의 복사본만 존재하며, 모든 인스턴스에서 이 복사본을 공유

import axios from 'axios';
import { server_url } from './serverConfig';

class TokenManager {
  private static instance: TokenManager;
  private tokenRefreshing: boolean = false;

  private constructor() {}

  public static getInstance(): TokenManager {
    if (!TokenManager.instance) {
      TokenManager.instance = new TokenManager();
    }
    return TokenManager.instance;
  }

  private async updateToken() {
    // 이미 갱신 중이면 중복 요청 방지
    if (this.tokenRefreshing) {
      return;
    }

    this.tokenRefreshing = true;

    try {
      const refreshToken = localStorage.getItem('refreshToken');
      if (refreshToken) {
        const response = await axios.post(
          `${server_url}/auth/updatetoken`,
          {
            refreshToken,
          },
          {
            headers: {
              Authorization: `Bearer ${localStorage.getItem('accessToken')}`,
            },
          }
        );

        if (response.data.accessToken) {
          localStorage.setItem('accessToken', response.data.accessToken);
          localStorage.setItem('refreshToken', response.data.refreshToken);
        }
      }
    } catch (error) {
      console.error('Failed to refresh token', error);
    } finally {
      this.tokenRefreshing = false;
    }
  }

  public startTokenUpdate() {
    // 15분마다 한 번씩 토큰 갱신 요청
    setInterval(() => {
      this.updateToken();
    }, 15 * 60 * 1000);
  }
}

export default TokenManager;

 

그럼 이전에 카프카를 싱글톤패턴을 적용했는데 이건 맞는 설계인가.

무슨 목적이었는가 -> 하나의 프로듀서, 컨슈머를 통해 메세지를 주고 받기를 원함.

자원관리, 서버 메모리 관리, 데이터 상태 공유 (푸시 요청마다 새로 프로듀서를 생성하는 것을 방지)

서버(싱글톤 카프카 프로듀서) 메세지 생성 -> 카프카 컨테이너 -> 알림 서버(컨슈머)

 

 

에러 일지

import * as cookieParser from 'cookie-parser';

TypeError: cookieParser is not a function

 에러를 생성함.
import cookieParser from 'cookie-parser';

cookie-parser에 들어가보니 이미

module.exports = cookieParser 

로 기본 내보내기로 되어 있었다.

 

express

@Res({ passthrough: true })
passthrough: true 옵션은 NestJS에서 Response 객체를 직접 제어하면서도 컨트롤러가 JSON 응답을 반환하도록 허용하는 기능을 제공

 

// HttpOnly 쿠키 설정
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure: true, // HTTPS에서만 동작 (개발 중에는 false로 설정 가능)
    sameSite: 'strict',
    path: '/',
  });

'React Native' 카테고리의 다른 글

react native [로그인, 회원가입, 로그아웃]  (0) 2024.08.01
공식 문서와 함께하는 리액트 네이티브 [1]  (0) 2024.08.01
react native [삽질 2]  (1) 2024.08.01
react native [1]  (0) 2024.07.31