我开发了一个 VS Code 插件,它可以在同一屏幕上的多个分屏编辑器中编写 React 组件的各个部分。
JSX 分离函数组件
大家好!我是一名前端开发人员,使用 React 已经超过 6 年了,我比较喜欢 React 和 Vue 的组合React + Mobx + CSS-in-JS。我的大部分项目都是用 React 开发的,但也有少数项目使用了 Vue,而且我也在关注 Vue 的一些新特性。
最近,我发现了 Vue 生态系统的一个有趣的新功能:拆分编辑器。
什么是拆分编辑器?
这是什么?这是名为VolarSplit Editors的全新 VS Code Vue 插件的一项功能,您可以安装 Volar并在 Vue 项目中体验它。以下是 Volar 的一个演示:

在演示中,点击Split Editors右上角的按钮,根据SFC 中的template/ style/script代码生成 3 个子编辑器,然后每个编辑器折叠不相关的代码。
起初,我只是觉得它很有趣。但经过思考和实验,我发现它也很有用。我的理解是:
它不仅使我们能够更加专注于开发每个组件中的某一类代码,而且还使我们能够轻松扫描和控制组件的整体代码,以处理不同类别代码之间的关系。
React 中拆分编辑器的可行性
因为我经常CSS in JS在 React 开发中编写样式,所以我想到了将这个想法与 React 结合起来的可行性。这个想法是,我们需要将 React 组件代码拆分成几个类别,放在同一个文件中,然后分别放入不同的拆分编辑器中,并将不相关的代码单独折叠起来。关于拆分形式,如果按照详细程度划分,可以分为以下几种情况:
一级
二级
如果划分更详细一些:
3级
事实上,还可以更详细一些:
- 组件逻辑代码
- 组件渲染(JSX)代码
- 样式代码
- 全局成员(常量、函数、自定义钩子等)
代码分类越细致,分屏编辑器的效果就越好。因为这样一来,每个编辑器就可以容纳更多不相关的代码,从而最大限度地减少垂直滚动的范围。
我的解决方法
目前,React 函数组件的语法非常自由。如果不引入任何代码结构规范,就很难完美地实现这个概念。这里,我将展示一个可行的解决方案,它可以实现上面提到的所有 1-3 级拆分形式。
实现这个想法应该不止一种方法。例如,我也在考虑基于常规函数组件语法的解决方案。但目前,本文中的方案已经能够完全实现拆分编辑器的理念。
这个解决方案需要在组件代码中添加一些约定,它使用了一个我最近开发的有趣的 React 函数组件 API:
类似 SFC 的 React 函数组件 API,用于管理 CSS-in-JS 和静态成员。

介绍
jsx-sfcJSX Separate Function Components ( SFC ) 是一个类似 React 的函数组件 API,用于管理 CSS-in-JS 和静态成员。它使用 TypeScript 编写,具有完全的类型安全,并且基于编译器优化,因此也易于使用🧙🏼♂️。
在线演示在此(CSS in JS使用twin.macro,可通过 Codesandbox体验类型提示/热重载/开发者工具)。
目前我正在计划开发 v2.0 版本,主要功能特性请点击此处查看。我会尽力减少破坏性改动。
特征
- ✨在 React 函数组件中,清晰地分离JSX 标签、逻辑、样式以及任何其他成员。
- 💫完全由 TypeScript实现的类型推断设计
- 🎉 支持所有 React Hooks
- 🔥 支持React 快速刷新
- 🔧 支持 React ESLint 插件
- 🔨 支持 React 开发工具
- ⚡渲染性能与常规函数组件类似,存在……
此 APIjsx-sfc完全基于 TypeScript,它是一种与常规函数组件语法的 TS 类型一致的替代方案。它可以被视为一种思维模型,其代码结构类似于SFC,但它用于用纯 JSX/TSX 文件编写 React 函数组件。动态演示:
此外,jsx-sfc这是一个必须配合编译器使用的 API,才能提升其渲染性能和对 React 生态系统的适应性。我已经有超过 4 个生产项目在使用它。详情请参阅其文档。
该 API 的 TS 类型定义(粗略版本):
function sfc<Props, ComponentData, Styles, Static>(
options: {
Component: (props?: Props & Styles & Static & { props: Props }) => ComponentData;
render?: (args: { data: ComponentData; props: Props; styles: Styles } & Static) => JSX.Element;
styles?: Styles;
static?: Static;
}
): React.FC<Props> & { Render: (data?: ComponentData), Component: React.FC<Props> } & Styles & Static;
实际的类型定义在这里。
用于写入的组件jsx-sfc如下所示:
import sfc from 'jsx-sfc';
import styled from 'styled-components';
const Todo = sfc({
Component({ value, styles: { Input } }) {
return <Input value={value} />;
},
styles: () => ({
Input: styled.input`
color: #000;
`
})
});
/* Equivalent regular syntax:
function Todo({ value }) {
return <Input value={value} />;
}
const Input = styled.input`
color: #000;
`;
Object.assign(Todo, { styles: { Input } });
*/
const App = () => <Todo value="test" />;
它还支持将组件的渲染部分编写在单独的函数中:
import sfc from 'jsx-sfc';
import styled from 'styled-components';
const Todo = sfc({
Component() {
const [value, setValue] = useState('test');
return {
value,
onChange(e) {
setValue(e.target.value);
}
};
},
render: ({ data, props, styles: { Input } }) => (
return <Input defaultValue={props.value} value={data.value} onChange={data.onChange} />;
),
styles: () => ({
Input: styled.input`
color: #000;
`
})
});
/* Equivalent regular syntax:
function Todo(props) {
const [value, setValue] = useState('test');
function onChange(e) {
setValue(e.target.value);
}
return <Input defaultValue={props.value} value={value} onChange={onChange} />;
}
const Input = styled.input`
color: #000;
`;
Object.assign(Todo, { styles: { Input } });
*/
const App = () => <Todo value="test" />;
此外,它还支持定义组件的静态成员:
函数组件的静态成员是什么?您可以参考这里。
import sfc from 'jsx-sfc';
import styled from 'styled-components';
const Todo = sfc({
Component({ hooks: { useInputValue } }) {
const [value, setValue] = useInputValue('test');
return {
value,
onChange(e) {
setValue(e.target.value);
}
};
},
static: () => {
function useInputValue(initial) {
const [value, setValue] = useState(initial);
return { value, setValue };
}
return {
hooks: {
useInputValue
}
};
},
render: ({ data, styles: { Input } }) => (
return <Input value={data.value} onChange={data.onChange} />;
),
styles: () => ({
Input: styled.input`
color: #000;
`
})
});
/* Equivalent regular syntax:
function Todo() {
const [value, setValue] = useInputValue('test');
function onChange(e) {
setValue(e.target.value);
}
return <Input value={value} onChange={onChange} />;
}
function useInputValue(initial) {
const [value, setValue] = useState(initial);
return { value, setValue };
}
const Input = styled.input`
color: #000;
`;
Object.assign(Todo, { hooks: { useInputValue }, styles: { Input } });
*/
// Using the static members
const App = () => {
const [value, setValue] = Todo.hooks.useInputValue('test');
return (
<>
<Todo />
<Todo.styles.Input />
</>
);
};
以上三种情况与上一节中提到的代码分割形式的三个层次完全对应。
我已经制作了一些使用此 API 管理不同 CSS-in-JS 库的示例,您可以在这里看到。
为 React 中的 Split Editors 开发了一个 VS Code 插件。
我还制作了一个类似思路的 VS Code 插件:vscode-jsx-sfc。它需要配合使用jsx-sfc,以下是演示:

与 Volar 类似,我们可以专注于在多个分屏编辑器中编写ComponentReact组件的render代码styles;同时,它还可以概览整个组件代码,从而减轻处理不同类别代码之间关系所带来的精神负担,并减少垂直滚动代码的长度。
如果您不习惯编写单独的渲染函数,拆分编辑器目前仍仅支持Component/ styles:

如果单个文件中定义了多个函数组件jsx-sfc,则在每个拆分编辑器中,不相关的代码将针对每个组件进行折叠:

如果使用 jsx-sfc 定义静态成员,它们将被拆分为Component and static//render形式styles:

如何快速体验
步骤 1:使用create-react-app创建一个示例项目:
npx create-react-app my-app
步骤 2:安装jsx-sfc.macro并styled-components:
cd my-app
npm install jsx-sfc.macro styled-components
步骤 3:将此代码复制到src/App.js:
import styled from 'styled-components';
import sfc from 'jsx-sfc.macro';
import logo from './logo.svg';
const App = sfc({
Component({ styles: { Wrapper }, ...props }) {
return (
<Wrapper>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
Learn React
</a>
</header>
</Wrapper>
);
},
styles: () => {
return {
Wrapper: styled.div`
text-align: center;
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
`
};
}
});
export default App;
步骤 4:在 VS Code 中安装vscode-jsx-sfcSplit Editors Icon (搜索“jsx-sfc”),然后单击代码视图编辑器右上角的图标,即可开始体验:

以上是在 CRA 中使用 Babel 宏进行体验的示例,其他框架如 Webpack、Rollup 和 Vite 也同样支持,只需进行相应替换即可jsx-sfc.macro。jsx-sfc详情请参见此处。
非常感谢您的阅读。
这个 VS Code 插件目前肯定还不完美,但已经可以尝试用于日常开发了。它的实现使用了 @vue/reactivity,与 Volar 相同。
欢迎体验这款有趣的工具并提出建议,代码仓库和文档链接如下:
类似 SFC 的 React 函数组件 API,用于管理 CSS-in-JS 和静态成员。
文章来源:https://dev.to/joesky/i-made-a-vscode-plugin-that-can-write-each-part-of-react-component-in-multiple-split-editors-on-the-same-screen-58a5