Do’s and Don’ts
Component patterns and coding conventions with clear examples. Use the rule numbers to reference guidelines in code reviews (e.g. “please follow Rule 1”).
Quick Reference
| # | Rule | Summary |
|---|---|---|
| 1 | Screens/Components | No nested screens/ folders |
| 2 | List/Detail Pattern | Use List and Detail suffixes |
| 3 | Index.tsx Convention | One folder per component with index.tsx |
| 4 | Component Names | Avoid redundant context in names |
| 5 | Utils Files | Use utils/ folder at shared level |
| 6 | Components Nesting | Keep nested components with parent |
| 7 | Constants | Colocate or use utils/constants/ |
| 8 | Import Preferences | Favor relative imports and TS aliases |
| 9 | useViewModel Pattern | Inject ViewModel as props |
Rule 1: Screens/Components
Folders inside screens/ cannot have their own screens/ subfolders. If a component is uniquely associated with a screen, place it in a components/ subfolder inside that screen folder.
Do:
Market/
├─ components/
│ └─ MarketRowItem/
└─ screens/
├─ MarketList/
│ └─ components/
│ └─ BottomSection/
└─ MarketDetail/Don’t:
Market/
└─ screens/
├─ MarketList/
│ └─ screens/ // ❌ No nested screens
└─ MarketDetail/Rule 2: List/Detail Pattern
- Suffix list components with
List(always singular) - Suffix detail components with
Detail
Do:
Market/
└─ screens/
├─ MarketList/
└─ MarketDetail/Don’t:
Market/
└─ screens/
├─ ListOfMarketItem/ // ❌ Wrong naming
└─ MarketItemPage/ // ❌ Wrong namingRule 3: Index.tsx Convention
Create a dedicated folder per component and name the main file index.tsx.
Do:
components/
└─ MarketRowItem/
├─ index.tsx
└─ useMarketRowItemViewModel.tsxDon’t:
components/
├─ MarketRowItem.tsx // ❌ No folder
└─ useMarketRowItemViewModel.tsx // ❌ Outside component folderRule 4: Component Names
Avoid redundant context in component names. The folder structure provides context.
Do:
features/Deposit/screens/SelectNetwork/useSelectNetworkViewModel.tsxDon’t:
features/Deposit/screens/DepositFlowSelectNetwork/useDepositFlowSelectNetworkViewModel.tsx
// ❌ "DepositFlow" is redundant - we're already in Deposit featureRule 5: Utils Files
Do not colocate utils as a single file. Use a utils/ folder and place it at the top level of components that import it.
Do:
Market/
├─ screens/
│ └─ MarketDetail/
├─ components/
│ ├─ Header/
│ └─ Footer/
└─ utils/
└─ index.tsx // Shared by MarketDetail, Header, FooterDon’t:
Market/
└─ components/
└─ Header/
├─ index.tsx
└─ utils.tsx // ❌ Utils as sibling fileRule 6: Components Nesting
If a component is not reused elsewhere, create it next to its parent. Do not flatten nested components.
Do:
MarketDetail/
├─ components/
│ └─ Stats/
│ ├─ Price/
│ │ └─ index.tsx
│ ├─ Supply/
│ │ └─ index.tsx
│ └─ index.tsx
└─ index.tsxDon’t:
MarketDetail/
├─ Stats/
│ └─ index.tsx
├─ Price/ // ❌ Flattened - unclear hierarchy
│ └─ index.tsx
├─ Supply/ // ❌ Flattened - unclear hierarchy
│ └─ index.tsx
└─ index.tsxRule 7: Constants
Colocate constants with their component. If shared between components, declare them in utils/constants/.
Do:
utils/
└─ constants/
└─ coins.ts // Shared by MarketDetail, MarketList, SendFlowDon’t:
MarketDetail/
├─ coins.ts // ❌ Local constant
└─ index.tsx
MarketList/
└─ index.tsx // Imports from ../MarketDetail/coins ❌Rule 8: Import Preferences
- Favor relative imports when not moving more than one folder up
- Favor TS aliases over absolute imports
- Add TS aliases when it improves readability
Do:
import MarketDetail from "LLM/features/Market/screens/MarketDetail";
import MarketDetail from "../MarketDetail";
import MarketDetail from "./MarketDetail";Don’t:
import MarketDetail from "src/features/Market/screens/MarketDetail"; // ❌ Absolute path
import MarketDetail from "../../../MarketDetail"; // ❌ Too many levels
import MarketDetail from "./MarketDetail/index.tsx"; // ❌ Explicit indexRule 9: useViewModel Pattern
Inject the ViewModel hook result as props to the View component. Do not call the ViewModel hook inside the component body.
Do:
// index.tsx - Inject ViewModel as props
const MarketDetail = () => <View {...useMarketDetailViewModel()} />;
// View.tsx - Receives pre-computed props
const View = ({ price, volume, onRefresh }: Props) => (
<Screen>
<Text>{price}</Text>
<Text>{volume}</Text>
<Button onPress={onRefresh}>Refresh</Button>
</Screen>
);Don’t:
// ❌ Don't call ViewModel inside the View component
const MarketDetail = () => {
const { price, volume, onRefresh } = useMarketDetailViewModel();
return (
<Screen>
<Text>{price}</Text>
<Text>{volume}</Text>
<Button onPress={onRefresh}>Refresh</Button>
</Screen>
);
};Why? Separating the ViewModel call from the View makes testing easier. You can test the View with different props without mocking hooks, and test the ViewModel logic independently.
See also
- MVVM Pattern — Full ViewModel implementation pattern
- Architecture — Folder structure and import rules
- How to Structure a Feature — Applying these rules when creating features