Upgrade to Pro — share decks privately, control downloads, hide ads and more …

フロントのディレクトリ構成

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

 フロントのディレクトリ構成

2022.07.29 LT会 古家さん発表資料

More Decks by PharmaX(旧YOJO Technologies)開発チーム

Other Decks in Technology

Transcript

  1. フロントのディレクトリ構成 1 フロントのディレクトリ構成 ├─ components/ │ ├─ elements/ │ │

    └─ button │ │ └─ Button.tsx │ │ └─ ButtonDisabled.tsx │ └─ layouts/ │ └─ header │ └─ Header.tsx │ └─ sideMenu │ └─ footer ├─ pages/ ├─ features/ │ └─ /messageList │ ├─ api/ │ └─ fetchMessageList.ts │ ├─ states/ │ ├─ constants/ │ ├─ components/ │ ├─ index.tsx │ ├─ MessageListHeader.tsx │ ├─ MessageListTalkBox.tsx │ ├─ MessageListTalkBoxMessage.tsx │ ├─ hooks/ │ └─ types/ │ └─ index.ts ├─ states/ ├─ constants/ ├─ hooks/ ├─ libs/ ├─ styles/ └─ types/ 各ディレクトリの役割 components elements アプリケーション全体で使う共通コンポーネントを置く。 例えばセレクトボックスなど。 具体例
  2. フロントのディレクトリ構成 2 /components/elements/select/SelectWithMultiple.tsx export const SelectWithMultiple: React.FC<Props> = ({ label,

    menuItemList, onChange }) => { const [isOpen, setIsOpen] = useState<boolean>(false); return ( <div> <Select isOpen={isOpen} onClick={() => setIsOpen(!isOpen)}> <div className="select__label"> {label} </div> <img className="select__pulldown-icon" src="/images/pulldown.svg" alt=" プルダウン" /> </Select> <MenuItemList style={{ display: isOpen === false ? 'none' : 'block' }}> {menuItemList.map((menuItem, index) => ( <MenuItem key={menuItem.id} > {menuItem.checked === true ? <MenuItemActiveCheckbox onClick={() => onChange(index, !menuItem.checked)}> <div className="menu-item__check-mark" /> </MenuItemActiveCheckbox> : <MenuItemCheckbox onClick={() => onChange(index, !menuItem.checked)} /> } <div className="menu-item__label" style={{color: menuItem.color ? menuItem.color : '' }}> {menuItem.label} </div> </MenuItem> ))}
  3. フロントのディレクトリ構成 3 </MenuItemList> </div> ); }; layouts アプリケーション全体で使うレイアウトコンポーネントを置く。 例えば、Header やFooter

    など 具体例 components/layouts/header/LayoutHeader.tsx export const LayoutHeader: React.FC = () => ( <Header> <div className="header-left"> <StaffProfile> <div className="staff-profile-left"> <img src="/images/dummyStaffProfileImg.svg" alt=" スタッフ画像" /> </div> <div className="staff-profile-right"> <div className="pharmacy-name">YOJO 薬局四⾕店</div> <div className="staff-name"> 養⽣KANAKO</div> </div> </StaffProfile> </div> <div className="header-right"> <PatientIcon> <div className="header-wrapper header-wrapper__patient-icon"> <img src="/images/patientIcon.svg" alt=" 患者" /> <div className="label"> 患者</div> </div> </PatientIcon> <StaffIcon> <div className="header-wrapper header-wrapper__staff-icon"> <img src="images/staffIcon.svg" alt=" スタッフ" /> <div className="label"> スタッフ</div> </div> </StaffIcon> <HeaderBorder /> <NotificationIcon> <div className="header-wrapper header-wrapper__notification-icon"> <img src="images/bell.svg" alt=" 通知" /> <div className="circle" /> </div> </NotificationIcon> </div> </Header> ); pages Next のページコンポーネントを⼊れる。 全体のページを表すもの 具体例
  4. フロントのディレクトリ構成 4 この場合はチャットが出来る画⾯なのでChatPage コンポーネント https://www.figma.com/file/1DvdJugCrzT5kkTW9FSSe8/UIdesign?node-id=613%3A786 const ChatPage = styled.div` display:

    flex; flex-direction: column; height: 100%; `; const Contents = styled.div` display: flex; justify-content: space-between; height: calc(100% - 101px); `; const Home: NextPage = () => ( <ChatPage> <LayoutHeader /> <Contents> <TalkRoomCardList /> <TalkContainer /> <PatientDetailInfo /> </Contents> </ChatPage> ); export default Home; features
  5. フロントのディレクトリ構成 5 ある特定の機能、ドメインでしか使わないapi へのアクセサや定数、型、hooks 、コンポーネントなど 全てを詰め込む。 状態はstore だとredux と紛らわしく、atom だとrecoil

    を知らない⼈がみた時にひと⽬で状態管理⽤ のディレクトリだと分かりにくいのでstates という命名にした。 features/components index.tsx から同ディレクトリのコンポーネントを読みこむルールで統⼀ index.tsx にstate をもたせる 命名はパスカルケース 機能名+ コンポーネント名にすることでこの機能に依存していることを表して、すぐに使ってい る場所が分かるようにする。 共通化したいUI パーツはルートディレクトリの/components のelement やlayout に置く メソッドを書く場所 onXXX などのイベントハンドラ系 コンポーネント内に書く formatXXX 、filteredXXX などの整形系 コンポーネントの外に書く 具体例
  6. フロントのディレクトリ構成 8 export const userState = atom({ key: 'user', default:

    { id: null, name: '', email: '' } }) constants アプリケーション全体の定数を置く 例:カラーコード、レイアウト系の定数 具体例 const colors = { main: { primary: { light: '#DBEEE3', main: '#7DB894', dark: '#569870', }, secondary: { light: '#838383', main: '#6A6A6A', dark: '#464646', }, }, warning: { positive: { light: '#DBEEE3', main: '#7DB894', dark: '#569870', }, negative: { light: '#FFE1E1', main: '#F39191', dark: '#D36A6A', }, }, sub: { a: { light: '#DFDC92', main: '#B9B552', dark: '#676418', }, b: { light: '#D4DEFF', main: '#839EFF', dark: '#3A51A3', }, }, text: { positive: { light: '#878787', main: '#4D4B4B', dark: '#2B2B2B', }, negative: { light: '#FFE1E1', main: '#F39191', dark: '#D36A6A', }, link: { light: '#DBEEE3', main: '#7DB894',
  7. フロントのディレクトリ構成 9 dark: '#569870', }, onDark: { light: '#E3E3E3', main:

    '#FFFFFF', dark: '#A5A5A5', }, }, background: { primary: { main: '#FFFFFF', dark1: '#F5F5F5', dark2: '#D9D9D9', dark3: '#707070', }, secondary: { main: '#DBEEE3', dark1: '#ACD3BC', dark2: '#7DB894', dark3: '#569870', }, }, }; export default colors; hooks アプリケーション全体で使⽤するcustom Hook を置く場所 ログインの状態を全ページで⾒るhook を全ページのroot で呼びだす 例:useRequireLogin.ts import { useEffect } from 'react' import { useRouter } from 'next/router' import { useFirebaseAuth } from 'util/firebase/client' /** * ログイン状態を確認し、未ログインの場合はログインページへリダイレクトするカスタムフック */ export const useRequireLogin = (): void => { const { user, authInitializing } = useFirebaseAuth() const router = useRouter() useEffect(() => { if (authInitializing) return if (!user) router.push('/') // ログイン画⾯へリダイレクト }, [authInitializing, user, router]) } libs ライブラリのラッパーなど Firebase のクライアントはここに置く
  8. フロントのディレクトリ構成 10 styles アプリケーション全体で反映したいスタイルを置く場所 CSS の初期設定 例:global.css * { box-sizing:

    border-box; } html { margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; max-width: 50rem; padding: 0.5rem; margin: 0 auto; font-size: 100%; } a { color: inherit; text-decoration: none; } types アプリケーション全体で使う型定義ファイル 独⾃の型定義ファイル、@types モジュールに無いライブラリの型定義ファイルなど Swagger で⾃動出⼒される型やfirestore の型を置いている