Container and Presentational filenames in React TypeScript

允我心安 提交于 2020-06-27 13:09:16

问题


I have a React site currently in JavaScript/ES that we are converting to TypeScript (🎉). We use the Container and Presentational breakdown, so each component will have either a Container and a Presentational file, or for simpler components just a Presentational file.

Over the course of a build, we will typically build "static" Presentational screens/components first, get them to pass design QA, and then make them dynamic by adding a Container. That means that the Presentational files are usually built first. Containers are built later, if needed.

Our directory structure looks like this:

components
├── SomeComponent
│   └── index.js
│   └── index.jsx
├── SomeOtherComponent
│   └── index.jsx

^^ Here we have SomeComponent which has Container+Presentational, while SomeOtherComponent has only Presentational.

This structure provides us with several benefits:

  1. Imports are short and not "doubled": import SomeComponent from '../screens/SomeComponent' (not import SomeComponent from '../screens/SomeComponent/SomeComponent')
  2. Imports do not need to change when Containers are eventually added. If only a Presentational .jsx file exists, the import above works. When/if a Container .js file is added, it then takes precedence over the .jsx, so the same import now targets the new file by virtue of it existing. (Webpack resolve.extensions = ['.js', '.jsx'])
  3. No need to rename the presentational component file when a Container is added. This keeps git history nicely intact.
  4. Quick & easy visual identification of which file is Container vs Presentational. Presentational is .jsx because that's where our JSX lives.
  5. We use react/jsx-filename-extension to enforce that JSX should only be in .jsx files. This gives our devs get an eslint warning if they try to write JSX in a .js Container file. This enforces the concept that Containers should do business logic (in JS), while Presentationals should just output "dumb" markup (in JSX).

Works great!

The only caveat, which in my opinion is very minor, is: In order for this to work, in our Containers we import the Presentational like so: import SomeComponent from './index.jsx'. I say this is a caveat simply because it's the only place where we import using a complete file extension. No big deal...

In TypeScript, I'd love to just change those file extension from js/jsx to ts/tsx like so:

components
├── SomeComponent
│   └── index.ts
│   └── index.tsx
├── SomeOtherComponent
│   └── index.tsx

But we have a problem: In TypeScript we cannot use file extensions in an import (to the best of my knowledge). So this breaks our ability to execute the "caveat," and seems to force us to have different filenames for the Containers vs Presentationals. 😭

How does your team solve this dilemma?

I have searched for conventions on how other teams navigate this issue, and have come up empty-handed.

I am open to criticism of any part of our convention here, and I invite discussion. This is a higher-level issue that also affects the lower-level day-to-day of our devs. All ideas are good ideas (except the ones that suck)!

A few ideas:

A) ts-ignore

Use // @ts-ignore above the import SomeComponent from './index.tsx' line to mute the error. This feels like bad practice, but what would be the consequences?

  • Pros:
    • Allows use of index.ts and index.tsx to mimic our previous setup
    • No need to rename presentationals when a container is added
    • No need to change imports when a container is added
  • Cons:
    • Feels like bad practice (🚩)
    • Have to remember to add it and instruct other devs to add it
    • Requires we add '@typescript-eslint/ban-ts-ignore': 'off' to our eslint conf, which by extension means eslint will no longer prevent people from using @ts-ignore anywhere they want. 😬
    • What else might this break? Does it kill intellisense? What other havoc would this wreak?

B) PascalCase Presentationals

components
├── SomeComponent
│   └── index.ts
│   └── SomeComponent.tsx
├── SomeOtherComponent
│   └── index.tsx
  • Pros:
    • Seems kindof conventional. Some teams use PascalCase for all component names as convention.
    • No need to change imports when a container is added.
  • Cons:
    • Requires renaming presentational file when container is added (messes with git history).
    • Not as easy to instantly identify which file is container vs presentational. There's a (small) logical leap that must be taken in your mind: "That one is named after the component and when they are named after a component they are presentational").
    • The two Container/Presentational files will not always be "next to" eachother in the directory. If another file named index.test.ts or index.stories.tsx or styles.js exists, it might be in-between index.ts and presentational.tsx

C) presentational.tsx

components
├── SomeComponent
│   └── index.ts
│   └── presentational.tsx
├── SomeOtherComponent
│   └── index.tsx
  • Pros:
    • No need to change imports when a container is added.
    • Instantly obvious which file is presentational. (Solves problem with B above)
  • Cons:
    • Requires renaming presentational file when container is added (messes with git history).
    • The two Container/Presentational files will not always be "next to" eachother in the directory. If another file named index.test.ts or index.stories.tsx exists, it will be in-between index.ts and presentational.tsx

D) index.presentational.tsx

components
├── SomeComponent
│   └── index.ts
│   └── index.presentational.tsx
├── SomeOtherComponent
│   └── index.tsx
  • Pros:
    • No need to change imports when a container is added.
    • Instantly obvious which file is presentational. (Solves problem with B above)
    • The two Container/Presentational files will always be "next to" eachother in the directory. (Solves problem with B & C above)
  • Cons:
    • Requires renaming presentational file when container is added (messes with git history).
    • Long filename (not sure I really care about this)

来源:https://stackoverflow.com/questions/62437380/container-and-presentational-filenames-in-react-typescript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!