Recoil selector를 통한 비동기식 데이터 조회

16731 단어 Recoil
개요
비동기 데이터 조회에서 Recoil의 selector를 사용한 상황에서 어떤 동작 실험을 진행합니까?
또한 코드는 여기서 동작을 확인할 수 있다
https://codesandbox.io/s/ecstatic-austin-k2c3z
응용 프로그램 설명
이른바 키워드 검색에 이름을 표시하는 프로그램만 있으면 된다.데이터가 네트워크를 통해 키워드 검색을 할 수 있도록 상상하십시오. (실제로는 로컬에서만 선별하고wait에서만 진행됩니다.)
검색 결과를 비동기적으로 불러오는 동안loading indicator가 검색 결과에 겹쳐집니다.


코드 해설
atom/selector의 정의
/**
 * states
 */
const keywordInputState = atom({
  key: "keywordInput",
  default: ""
});

const keywordState = atom({
  key: "keyword",
  default: ""
});

const searchResultState = selector({
  key: "searchResult",
  async get({ get }) {
    const keyword = get(keywordState);
    const results = await searchEntries(keyword);
    return results;
  }
});
키워드를 표시하는 입력의tom(keywordInputState과 확정된 키워드를 표시하는tomkeywordState, 키워드 검색 결과를 표시하는selectorsearchResultState를 준비합니다.searchResultState 확정된 키워드를 이용하여 비동기 호출searchEntries()을 호출하여 그 결과를 되돌려주는 selector가 된다.
어셈블리 정의
키워드 입력 및 검색 프로세서
function KeywordSearchForm() {
  const [keywordInput, setKeywordInput] = useRecoilState(keywordInputState);
  const onSearch = useRecoilCallback(async ({ getPromise, set }) => {
    const keyword = await getPromise(keywordInputState);
    set(keywordState, keyword);
  }, []);
  return (
    <div className="search-form">
      <input
        type="text"
        value={keywordInput}
        onChange={e => setKeywordInput(e.target.value)}
        onKeyDown={e => (e.keyCode === 13 ? onSearch() : null)}
      />
      <button onClick={onSearch}>Search</button>
    </div>
  );
}
keywordInputState 참조useRecoilState를 통해 키워드의 입력 상태를 제어합니다.물론 이렇게useState도 되고, 그렇다면 uncontrolled도 되고, 어쨌든.Enter 키를 누를 때 Search 버튼을 누를 때onSearch() 프로세서가 작동합니다.onSearch()에서 keywordInputState의 값만 읽고 키워드 확인keywordState으로 설정합니다.
검색 결과 표시
function SearchResult() {
  const searchResultLoadable = useRecoilValueReplayLoadable(searchResultState);
  const searchResult = searchResultLoadable.getLastResolvedValue();
  return (
    <div className="result">
      {searchResult ? (
        <ul className="list">
          {searchResult.map(item => (
            <li>{item.name}</li>
          ))}
        </ul>
      ) : (
        undefined
      )}
      {searchResultLoadable.state === "loading" ? (
        <div className="loading">
          <span>loading...</span>
        </div>
      ) : (
        undefined
      )}
      {searchResultLoadable.state === "hasError" ? (
        <div className="error">{searchResultLoadable.contents.message}</div>
      ) : (
        undefined
      )}
    </div>
  );
}
검색 결과는 참조searchResultState의 훅스를 이용한다.비동기 마운트 상태를 확인하기 위해 대상을 가져옵니다 Loadable.물론 useRecoilValue에서 직접 값을 얻을 수도 있지만 이 경우<Suspense>는 포위되어야 한다.
또 직접 사용useRecoilValueLoadable이 아니라 후술처럼 이용useRecoilValueReplayLoadable의 사용자 정의 갈고리를 사용했다.
전체 애플리케이션
export default function App() {
  return (
    <div className="App">
      <KeywordSearchForm />
      <SearchResult />
    </div>
  );
}
사용자 지정 바닥글
리코일의 경우 비동기 처리에서 <Suspense>로 구성 요소를 둘러싸고 대체 내용을 표시할 수 있지만 같은 구성 요소의 지난번 결과를 직접 표시하기는 어렵다.또 정부useRecoilStateLoadable에서 비동기 전의 해결치를 직접 얻을 수 없다.따라서 최종 해결 값Loadable을 얻기 위해 대상에 사용getLastResolvedValue() 방법의 사용자 정의 연결을 준비했다.
import { useRef, useEffect } from "react";
import { useRecoilValueLoadable, Loadable, RecoilValue } from "recoil";

type ReplayLoadable<T> = Loadable<T> & {
  getLastResolvedValue(): T | undefined;
};

export function useRecoilValueReplayLoadable<T>(
  state: RecoilValue<T>
): ReplayLoadable<T> {
  const loadable = useRecoilValueLoadable(state);
  const lastValueRef = useRef<T>();
  useEffect(() => {
    if (loadable.state === "hasValue") {
      lastValueRef.current = loadable.contents;
    }
  }, [loadable]);
  return {
    ...loadable,
    getLastResolvedValue() {
      return this.state === "hasValue" ? this.contents : lastValueRef.current;
    }
  };
}
여기서는 Conceurent ModeuseTransition를 사용하면 원활하게 사용할 수 있습니다.
실험
캐시 정보
상기 프로그램의 키워드를 바꾸어 검색해 보십시오.searchEntries() 1sec 정도의wait를 강제로 사용하지만 서로 다른 키워드로 검색한 후 같은 키워드로 한 번 검색하면 검색 결과를 즉시 되돌려줍니다.
이로써 비동기적인 selector라도 계산 결과는 캐시된다는 것을 알 수 있다.또한state 이전의 값에 의존할 뿐만 아니라 모든 변화가 가능합니다state 값의 결과는 memo의 것임을 알 수 있다.
비동기 오류 정보
실제로searchEntries()는 1/10의 확률로 오류를 되돌려준다(네트워크 오류 등을 가정한다).이것은 무작위로 같은 키워드로 검색하면 오류가 발생하지 않을 수 있지만 잘못된 같은 키워드로 다시 검색하면 무조건 실시간 오류가 발생할 수 있다.이로써 비동기 처리에서 발생하는 오류도 캐시된다는 것을 알 수 있다.
현재queryversion과 같은tom을 준비하여 캐시를 강제로 무효화(실제로는 memoization 키만 변경)하는 의존성 사전 제작searchResultStateselector를 준비할 필요가 있다.

좋은 웹페이지 즐겨찾기