Synchronizing URLs to Form State

김동현·2023년 3월 21일
0

React Router

목록 보기
23/31

몇 가지 UX에 관한 문제가 있다.

  1. 검색후 뒤로가기 버튼을 누른다면, 목록은 필터링 되기 전으로 돌아가지만 검색 필드에는 입력한 값이 그대로 남아있다.

  2. 검색후 새로고침을 누르면 목록은 필터링이 그대로 되어있지만 검색 필드에는 입력한 값이 사라진다.

목록 필터링은 원하는 대로 되지만, 검색 필드가 말썽이다.

즉, URL과 form 상태가 동기화되지 않는다.

Return "q" from your loader and set it as the search field default value

// 📄src/routes/root.jsx

// existing code

export async function loader({ request }) {
  const url = new URL(request.url);
  const q = url.searchParams.get("q");
  const contacts = await getContacts(q);
  return { contacts, q };
}

export default function Root() {
  const { contacts, q } = useLoaderData();
  const navigation = useNavigation();

  return (
    <>
      <div id="sidebar">
        <h1>React Router Contacts</h1>
        <div>
          <Form id="search-form" role="search">
            <input
              id="q"
              aria-label="Search contacts"
              placeholder="Search"
              type="search"
              name="q"
              defaultValue={q}
            />
            {/* existing code */}
          </Form>
          {/* existing code */}
        </div>
        {/* existing code */}
      </div>
      {/* existing code */}
    </>
  );
}

위와 같이 하면 2번 문제는 해결된다.

새로 고침을 해도 검색 필드의 값이 사라지지 않는다.
결과화면

1번 문제는 useEffect 를 이용해서 직접 DOM의 폼 상태를 조작하는 것으로 해결할 수 있다.

Synchronize input value with the URL Search Params

// 📄src/routes/root.jsx

import { useEffect } from "react";

// existing code

export default function Root() {
  const { contacts, q } = useLoaderData();
  const navigation = useNavigation();

  useEffect(() => {
    document.getElementById("q").value = q;
  }, [q]);

  // existing code
}

물론 DOM을 직접 조작하는 것 보다 Controlled Component와 React State를 사용해도 된다.

리액트에서는 controlled component의 사용을 적극 권장하지만, 이 경우 코드가 좀 더 복잡해 질 수 있으니 판단하에 사용하도록 한다.

controlled component와 react state를 이용한 코드는 아래와 같다.

// 📄src/routes/root.jsx

import { useEffect, useState } from "react";
// existing code

export default function Root() {
  const { contacts, q } = useLoaderData();
  const [query, setQuery] = useState(q);
  const navigation = useNavigation();

  useEffect(() => {
    setQuery(q);
  }, [q]);

  return (
    <>
      <div id="sidebar">
        <h1>React Router Contacts</h1>
        <div>
          <Form id="search-form" role="search">
            <input
              id="q"
              aria-label="Search contacts"
              placeholder="Search"
              type="search"
              name="q"
              value={query}
              onChange={(e) => {
                setQuery(e.target.value);
              }}
            />
            {/* existing code */}
          </Form>
          {/* existing code */}
        </div>
        {/* existing code */}
      </div>
    </>
  );
}

출처 : 리액트 라우터 공식 홈페이지➡️

profile
프론트에_가까운_풀스택_개발자

0개의 댓글