[Next.js] 구성 요소 및 상태 관리를 위한 파일 분할 및 설계

49141 단어 Next.jsReacttech

개시하다


지금까지 나는 어떻게 설치해야 할지 몰라서 조사를 진행하여 시행착오를 쓴 후에 실현된 방법을 썼다
이번에는 이룰 수 있지만 더 나은 이룰 수 없을까?나는 이 방향으로 한번 쓰고 싶다.
쓴 내용은 Next입니다.js에서 구현된 일람과 검색 기능을 가진 화면의 구성 요소와 상태 관리에 대한 파일 분할과 디자인.
넥스트입니다.js(React)에 관해서 제가 처음에 썼을 때는 1년 정도밖에 안 됐는데 업무상 쓴 적이 없어서 다른 PJ의 구성을 거의 몰랐지만 제 마음속의 디자인이 안정적이어서 쓰고 싶었어요.🙏

설명할 페이지


이번 해설의 페이지는 캐릭터와 LP로 자신이 실행한 트위터를 검색할 수 있는 깨알 독서 일람이 가능한 페이지다.
다음은 이 페이지의 신구 문서 구성과 상태 관리의 디자인에 대해 설명한다.
https://enjoy-sfv-more.com/lounge/tweet

구형


먼저 낡은 디자인의 문서 구성을 소개한다.
  • components
  • common
  • details.tsx
  • button.tsx
  • lounge
  • tweet
  • character.tsx
  • lp.tsx
  • list.tsx
  • item.tsx
  • lib
  • lounge
  • tweet
  • api.ts
  • pages
  • lounge
  • tweet.tsx
  • pages/lounge/tweet.tsx를 기준으로 사용하는 API와 어셈블리는 동일한 디렉토리 구조입니다(일부 공통 어셈블리도 있음).

    페이지


    페이지 파일에서 useState로 깨진 생각의 일람, 검색을 관리하는 조건(캐릭터와 LP).
    검색된 각 구성 요소components/lounge/tweet/character.tsx에서 사용자가 선택한 조건components/lounge/tweet/lp.tsx을 받아들여 상태를 유지합니다.
    검색을 누르면 저장된 검색 조건을 이용하여 검색 처리를 합니다.
    pages/lounge/tweet.tsx
    export default function LoungeTweet() {
      const [tweetList, setTweetList] = useState([]);
      const [allTweetList, setAllTweetList] = useState([]);
      const [selectCharacterList, setSelectCharacterList] = useState([]);
      const [selectLpList, setSelectLpList] = useState([]);
    
      useEffect(() => {
        (async () => {
          const tmpTweetList = await getTweet(); // lib/lounge/tweet/api.ts
          setTweetList(tmpTweetList);
          setAllTweetList(tmpTweetList);
        })();
      }, []);
      
      const search = () => {
        const searchTweetList = allTweetList.filter((tweet) => {
          // 検索処理
        });
        setTweetList(searchTweetList);
      };
      
      const changeCharacter = (characterList) => {
        setSelectCharacterList(characterList);
      };
    
      const changeLp = (lpList) => {
        setSelectLpList(lpList);
      };
    
      return (
        <Layout>
          <H1>ラウンジ募集呟き一覧</H1>
          <div>
            <Character changeCharacter={changeCharacter} /> {/* components/lounge/tweet/character.tsx */}
            <Lp changeLp={changeLp} /> {/* components/lounge/tweet/lp.tsx */}
            <Button onClick={search}>検索</Button> {/* components/common/button.tsx */}
            <LoungeList tweetList={tweetList} /> {/* components/lounge/tweet/list.tsx */}
          </div>
        </Layout>
      );
    }
    

    구성 요소


    캐릭터와 LP의 검색 성분이 거의 같기 때문에 LP의 성분을 소개해 드리겠습니다.
    검색 조건을 표시하고 검색 조건을 클릭한 후 구성 요소setXXX에서 상태를 유지하고 setXXX에서 받은 함수(이번 예는props를 실행하며 검색 조건을 부모에게 전달합니다.
    components/lounge/tweet/lp.tsx
    export default function LoungeTweetLp(props) {
      const { changeLp } = props;
      const [selectLpList, setSelectLpList] = useState([]);
    
      const clickLp = (lp) => {
        let tmpSelectLpList = [];
        if (selectLpList.includes(lp)) {
          tmpSelectLpList = selectLpList.filter((l) => l.id !== lp.id);
        } else {
          tmpSelectLpList = [...selectLpList, lp];
        }
        setSelectLpList(tmpSelectLpList);
        changeLp(tmpSelectLpList);
      };
    
      return (
        <div>
          <Details
            summary={(
              <div>
                <span>LP</span>
                <p>
    	      {selectLpList.length === 0 ? '指定なし' : selectLpList.map((selectLp) => (
                    <p>{selectLp.name}</p>
                  ))}
    	    </p>
              </div>
            )}
          >
            <ul>
              {lps.map((lp) => (
                <li>
                  <input type="checkbox" id={lp.id} onChange={() => clickLp(lp)} checked={selectLpList.includes(lp)} />
                  <label htmlFor={lp.id}>{lp.name}</label>
                </li>
              ))}
            </ul>
          </Details>
        </div>
      );
    }
    

    해설


    첫 번째 피쳐는 시트 어셈블리의 상태를 유지합니다.
    설치할 때 연결고리를 구성 요소 밖으로 뽑아서 쓸 수 있는지 몰라서 구성 요소에 적혀 있습니다.
    나는 단지 독립된 고리만 한 번 보았을 뿐 전혀 이해하지 못했다.
    https://ja.reactjs.org/docs/hooks-custom.html
    또한 각 페이지 구성 요소는 검색 조건의 상태를 유지합니다.
    검색 처리는 페이지에서 이루어지기 때문에 구성 요소에 검색 조건을 가지고 있을 필요는 없지만, 실행할 때 '구성 요소 안에 선택한 조건을 표시합니다' = '구성 요소 안에 표시된 조건이 있습니다'.
    나는 이 디자인에 다음과 같은 과제가 있다고 생각해서 팩스를 결정했다.
  • 페이지 구성 요소에서 표시와 관련된 처리와 상태와 관련된 처리의 두 가지 유형을 설명합니다
  • 파일 하나에 여러 가지 기능이 있고 복잡성이 높음
  • 파일이 커질 수 있음
  • 상태의 논리적 테스트는 쓰기 어려움
  • 각 페이지 구성 요소에 검색 조건이 있음
  • 복잡성이 높음
  • 지금


    새 디자인 제작changeLp으로 상태 관리와 관련된 처리를 구성 요소 밖으로 제출합니다.
  • components
  • common
  • details.tsx
  • button.tsx
  • lounge
  • tweet
  • character.tsx
  • lp.tsx
  • list.tsx
  • item.tsx
  • hooks
  • lounge
  • useTweet.ts
  • lib
  • lounge
  • tweet
  • api.ts
  • pages
  • lounge
  • tweet.tsx
  • 연결시키다


    페이지 구성 요소에서 쓴 상태를 저장하는 처리, 검색 조건의 디스플레이 텍스트, 검색 처리 등을 총괄했다.
    기본적으로 낡은 코드에서 복사된 것으로 새 것이 없다.
    hooks/lounge/useTweet.ts
    export const useLoungeTweet = () => {
      const [tweetList, setTweetList] = useState([]);
      const [allTweetList, setAllTweetList] = useState([]);
    
      const [selectLpList, setSelectLpList] = useState([]);
    
      const DEFAULT_TEXT = '指定なし';
      const [selectLpText, setSelectLpText] = useState(DEFAULT_TEXT);
    
      useEffect(() => {
        (async () => {
          const tmpTweetList = await getTweet();
          setTweetList(tmpTweetList);
          setAllTweetList(tmpTweetList);
        })();
      }, []);
    
      const search = () => {  
        const searchTweetList = allTweetList.filter((tweet) => {
          // 検索処理
        });
        setTweetList(searchTweetList);
      };
    
      const setSelectLp = (lp) => {
        let tmpSelectLpList = [];
        if (selectLpList.includes(lp)) {
          tmpSelectLpList = selectLpList.filter((l) => l.id !== lp.id);
        } else {
          tmpSelectLpList = [...selectLpList, lp];
        }
        setSelectLpList(tmpSelectLpList);
    
        if (tmpSelectLpList.length === 0) {
          setSelectLpText(DEFAULT_TEXT);
        } else {
          setSelectLpText(tmpSelectLpList.map((_lp) => {
            return _lp.name;
          }).join('\n'));
        }
      };
    
      const checkedLp = (lp) => {
        return selectLpList.includes(lp);
      };
    
      return {
        tweetList,
        selectLpText,
        setSelectLp,
        checkedLp,
        search,
      };
    };
    

    페이지


    상태 관련 처리 및 읽어들이기 처리hooks/lounge/useTweet.ts가 없으며 이 프로세스만 가져와 각 어셈블리에 전달할 수 있습니다.
    pages/lounge/tweet.tsx
    export default function LoungeTweet() {
      const {
        tweetList,
        search,
        setSelectCharacter,
        setSelectLp,
        checkedLp,
        checkedCharacter,
        selectCharacterText,
        selectLpText,
      } = useLoungeTweet();
    
      return (
        <Layout>
          <H1>ラウンジ募集呟き一覧</H1>
          <div>
            <Character set={setSelectCharacter} checked={checkedCharacter} text={selectCharacterText} />
            <Lp set={setSelectLp} checked={checkedLp} text={selectLpText} />
            <Button onClick={search}>検索</Button>
            <LoungeList tweetList={tweetList} />
          </div>
        </Layout>
      );
    }
    

    구성 요소


    상태에 대한 처리가 사라짐useLoungeTweet, 받은 것만 사용.
    components/lounge/tweet/lp.tsx
    export default function LoungeTweetLp(props) {
      const { text, set, checked, } = props;
    
      return (
        <div>
          <Details
            summary={(
              <div>
                <span>LP</span>
                <p>{text}</p>
              </div>
            )}
          >
            <ul>
              {lps.map((lp) => (
                <li>
                  <input type="checkbox" id={lp.id} onChange={() => set(lp)} checked={() => checked(lp)} />
                  <label htmlFor={lp.id}>{lp.name}</label>
                </li>
              ))}
            </ul>
          </Details>
        </div>
      );
    }
    

    해설


    홀로 갈고리 상태의 처리 등 통일, 낡은 디자인의 과제가 해결됐다.
  • 페이지와 구성 요소는 디스플레이 처리에만 사용되고 간단해집니다.
  • 파일의 비대화는 이전에 비해 억제되었다
  • 테스트는 이전 테스트보다 쓰기 쉽습니다
  • 중복 유지 안 함
  • 재활용 정보


    낡은 것과 새로운 페이지의 재사용은 그다지 고려되지 않는다.
    이번 해설은 일람과 검색의 페이지로 이 사이트에도 제작된 페이지가 있다.
    https://enjoy-sfv-more.com/lounge/create
    목록 및 검색 페이지와 비슷한 UI 구성 요소가 있으며 이제 다른 파일에서 사용할 수 있습니다.
    또 다른 이유로 이번 코드에는 나타나지 않았고props 등의 유형 정의와 재사용은 미묘한 차이를 흡수하기 위한 조건 지점이 구성 요소로 늘어날 것으로 보인다.
    이 사이트에서 페이지를 넘기는 재활용에 관해서 저는 아직 좋은 점을 찾지 못했습니다. 앞으로 수정하는 과정에서 좋은 곳에 떨어지면 다시 쓰고 싶습니다.

    최후


    다른 디자인을 더 알고 싶으니 마음대로 평론해 주세요.👍

    추기 2021/10/27


    나는 본 블로그에서 제작한 훅스 테스트에 관한 블로그를 썼다.
    https://zenn.dev/tiwu_dev/articles/0a0fb02aae92c0

    좋은 웹페이지 즐겨찾기