TIL: 무한스크롤, lazy loading, WebAPP, 상태 관리

Snoop So·2023년 6월 14일
0

무한스크롤

  • lazy loading은 성능 개선할 때 많이 쓴다.
  • modal을 띄울때 그제서야 그 컴포넌트를 가져오는 것도 방법임.
  • daynamic import
  • react lazy를 어떻게 쓰는지 보면 비슷한 원리이다
  • react suspence 를 쓰면 컴포넌트 단위의 복잡한 로직을 처리해줌
  • fallback 주면 그동안의 대체 컴포넌트를 지정할 수 있다.

Dynamic import

WepApp 인터랙션

  • swaping
  • 뒤로가기가 잘 되어야 함
  • 디바이스 구분해서 이벤트를 분기처리해야 함.

모바일 웹 디버깅

  • pc 와 연결해서 디버깅할 수 있음

상태 관리

Redux라는 것을 쓰면 모두 전역 상태로 만들게 됨. 이것은 좋은 방법은 아님. 큰 프로젝트 같은 경우 리덕스 코드가 있으면 상태가 너무 많아 지옥을 경험하게 됨.. 홀홀 전역 상태라는 것은 없으면 더 좋다.

그러면 전역 상태는 무엇이 되어야 하나? 사용자.

참고

//Provider
const store = createStore(rootReducer)
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)


//Consumer
import React from 'react'
import { useSelector } from 'react-redux'

export const CounterComponent = () => {
  const counter = useSelector((state) => state.counter)
  return <div>{counter}</div>
} // useSelector가 생겼다

Compoisiton

  • 함수 합성 기법처럼 컴포넌트도 합성할 수 있음.
function FirstComponent({ children }) {
  return (
    <div>
      <h3>I am the first component</h3>;
     { children }
    </div>
  );
}

function SecondComponent({ children }) {
  return (
    <div>
      <h3>I am the second component</h3>;
     {children}
    </div>
  );
}

function ThirdComponent({ children }) {
  return (
    <div>
      <h3>I am the third component</h3>
        {children}
    </div>
  );
}

function ComponentNeedingProps({ content }) {
  return <h3>{content}</h3>
}

export default function App() {
  const content = "Who needs me?";
 return (
    <div className="App">
      <FirstComponent>
        <SecondComponent>
          <ThirdComponent>
            <ComponentNeedingProps content={content}  />
          </ThirdComponent>
        </SecondComponent>
      </FirstComponent>
    </div>
  );
}

children을 줘서 props drilling 을 해결함

Flux 아키텍처

  • useReducer 에 너무 많은 상태가 묶이면 불필요한 렌더링이 발생한다.
  • 관리도 힘들어진다.

Server와의 상태 동기화

  • 서버에서 데이터를 가져왔어. 리덕스에 넣어놨어. 받은걸 바로 컴포넌트에 주면 안되나...?
  • 데이터가 서버와 연결되어 있는 상태일 경우..!
  • 통신 전후에 처리해야 할 것이 많아 관리가 어려워짐!
  • 서버와의 통신은 오래 걸림. 캐시를 잘해야 함
  • 각각의 컴포넌트에서 fetching 하면 어떨까? 그리고 다른 자식 컴포넌트에 반영되면 어떨까?
  • url을 기반으로 유니크한 키를 생성하고 그 키를 구독하고 있는 컴포넌트가 렌더링되게끔.
  • 상태를 공유중인 컴포넌트들의 부모에서 data fetching 하지말고 각자 그냥 하라.
  • URL 기준으로 캐시해서 중복요청하지 않음
  • 적절한 시간의 데이터 갱신을 위한 refresh

Redux Middleware

- 흐름은 유지되면서 미들웨어를 통해 중간에 서버로 갔다옴 - generate 함수라는 것은 함수를 멈추게 하는데, redux 내부에서는 이 함수를 사용함.

LRU

LRU (Least Recently Used)
운영체제의 페이지 교체 알고리즘 중 하나이다. 페이지를 교체할 때 가장 오랫동안 사용되지 않은 페이지를 교체 대상으로 삼는 기법이다.

캐시가 위험한 이유

  • 결국 최신성의 문제가 있음. 성능 문제 때문에 안하는 것임. 캐시 갱신이 잘 지원되어야 문제가 되지 않음.
  • 갱신하면 캐시를 무효화함

SWR

  • SWR이란 “Stale-While-Revalidate”라는 HTTP 캐시 무효화 전략에서 유래된 데이터 페칭을 위한 리액트 라이브러리이다.
  • 59초 동안은 캐시 데이터 써도 됨, 59초가 지나면 불러와.. 이런 식으로 정책을 만들 수 있음.
  • revalidate : 재확인하다
  • stale: 탁한 (최신이 아닌)

Mutation

  • 상태 업데이트하는 것
//fetch util
const updateLabel = (id, inputValue) => {
	return fetch(`http://localhost:3001/label/${id}`, {
		method: 'PATCH',
		headers: { 'Content-Type': 'application/json' },
		body: JSON.stringify({ description: inputValue }),
	}).then((res) => res.json());
};


//Component
export const LabelList = ({ id, name, description }) => {
	const queryClient = useQueryClient();
	const [isEditingMode, setEditingMode] = useState(false);
	const [inputValue, setInputValue] = useState('');

	const PatchMutation = useMutation((idx) => updateLabel(idx, inputValue), {
		onSuccess: (data, variables, context) => {
		    // 캐시 업데이트 (캐시 무효화)
                    queryClient.invalidateQueries('labels');
                    setEditingMode(false);
		},
	});

  //event handler
	const updateList = ({target}) => {
		const idx = target.closest('li').dataset.idx;
		PatchMutation.mutate(idx);
	};
  .....
 ......

atom 기반 상태관리

  • recoil 은 조각조각 상태를 만들고 그걸 공유함
  • Recoil 은 연결된 컴포넌트들이 불필요하게 렌더링되지 않는다.
//Atom.js
import { atom } from "recoil";

export const numState = atom({
  key: "count",
  default: 1
});

export const clickCountAtom = atom({
  key: "clickCount",
  default: 0
});

export const authenticationAtom = atom({
  key: "authentication",
  default: false
});


// View.js
import { useRecoilState } from "recoil";
import { clickCountAtom, authenticationAtom } from "./atoms/atoms";

const ClickCountView = () => {
  console.log("clickCountvIEW CALLED");
  const [clickCount] = useRecoilState(clickCountAtom);
  return (
    <>
      <div>클릭 횟수 : {clickCount}</div>
      <PrivateView />
    </>
  );
};
  • useRef를 생성해서 context api로 포함
  • useEffect에서 강제로 렌더링시켜버림

해봐야 할 것

  • react query 해보기
  • 조타이, 주스탄트

useSyncExternalStore

https://react.dev/reference/react/useSyncExternalStore
상태 관리 라이브러리의 기능을 표준화해서 만들어두는 작업을 리액트가 계속 진행중임

state machine

  • 상태를 가지고 시스템을 모델링하고 설계하는 데 사용되는 개념
  • 시스템이 특정 상태에서 다른 상태로 전이되는 모델
  • finite state machine(FSM)이라고도 불림, 유한한 개수의 상태와 전이로 구성
  • state -> event -> action -> transition 흐름으로 제어
  • statecharts 형태로 데이터 정의 (JSON 포멧 지원)

state

event

action

  • 데이터를 가져오거나, 상태를 직접 변경하는 비즈니스 로직 수행

transitions

  • 어떤 이벤트가 어떤 상태를 어떻게 변경시킬지 고민
  • 예) open 또는 closed 상태에서 issueSelected 이벤트 발생 시 changeState 액션 실행

Atomic design

에러 처리

  • 에러 처리, 테스트 하기
  • 개발자용 에러
    - 개발자에게 빠르게 문제를 찾아서 알려줄 수 있도록 한다. 친절보다는 원인 알려주기
  • 사용자용 에러 (Guided error handling)
    - 사용자용 에러: 사용자에게 에러를 알려주지 않고, 다음 행동을 유도한다.
  • 500, 400번대 에러일 경우... 처리
  • 에러는 다 전파됨. catch도 promise 를 반환한다.

https://velog.io/@cookie004/%EB%B2%88%EC%97%AD-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%90%EB%9F%AC-%ED%95%B8%EB%93%A4%EB%A7%81-%EB%B0%A9%EB%B2%95-%EC%86%8C%EA%B0%9C

Error boundary

https://legacy.reactjs.org/docs/error-boundaries.html
https://codepen.io/gaearon/pen/wqvxGa?editors=0010

  • 에러가 감지되면 해당 곳으로 가서 처리해줌

0개의 댓글