A few days ago, I got a question, why does React use JSX syntax, which makes the code seem "very coupled". According to tradition, it is recommended to separate html, js, and css templates. Where is the superiority of this design?
1. What is jsx?
JSX , the abbreviation of javascript Xml, is a syntactic sugar provided by Facebook's open source React framework, which can use HTML language in JS.
Official website original text:
JSX is an XML-like syntax extension to ECMAScript without any defined semantics. It’s NOT intended to be implemented by engines or browsers. It’s NOT a proposal to incorporate JSX into the ECMAScript spec itself. It’s intended to be used by various preprocessors (transpilers) to transform these tokens into standard ECMAScript.
2. Why are some component libraries using jsx/tsx?
For JSX
and template
(template rendering), it is recommended to template
use (especially in business scenarios). Vue 3 has done a lot of optimization based on template
the analysis , and it is transparent to the user, and the compiler has completed all the optimization operations silently. If you JSX
use , you need to manually perform some optimization operations.
For example, why the Vant component library chooses JSX, the main reason is that the component library code is more dynamic than the business code, and using JSX can flexibly control dynamic DOM fragments.
For example, suppose there is a scene where it is props
necessary reverse
to decide whether to swap the rendering order of two pieces of content based on the property on the .
This can be easily achieved in JSX:
const renderContent = () => {
const Content = [
<div class="foo">Foo DOM...</div>,
<div class="bar">Bar DOM...</div>,
];
if (props.reverse) {
Content.reverse();
}
return <div>{
Content}</div>;
}
If implemented through templates, without abstracting subcomponents, the template structure of foo and bar needs to be written twice to meet this requirement:
<template>
<div>
<template v-if="reverse">
<div class="bar">Bar DOM...</div>
<div class="foo">Foo DOM...</div>
</template>
<template v-else>
<div class="foo">Foo DOM...</div>
<div class="bar">Bar DOM...</div>
</template>
</div>
</template>
Therefore, in highly dynamic scenarios, JSX will have certain advantages.
In general:
Composition API + template
is the most cost-effective option.
Composition API + JSX
It is the ultimate choice in some scenarios, and correspondingly more development costs are required. JSX excels in flexibility, and in some situations with high dynamic requirements, JSX has become the standard configuration.
3. Get started quickly with jsx/tsx
In JSX expressions, 小括号 ( )
wrapping JSX
code is used 大括号 { }
to embed dynamic values. For usage in vue, see: rendering function & JSX
Vue's type definitions also provide type inference support for TSX syntax. When using TSX syntax, make sure to configure it
tsconfig.json
in"jsx": "preserve"
so that TypeScript can guarantee the integrity of the Vue JSX syntax compilation process.
v-if
- Only
v-show
instructions , there are nov-if
instructions - Both can be achieved using
if/else
and ternary expressions
template:
<div>
<div v-if="ok">yes</div>
<span v-else>no</span>
</div>
jsx:
<div>
{ok.value ? <div>yes</div> : <span>no</span>}
</div>
vue3 example:
setup() {
const isShow = false
const element = () => {
if (isShow) {
return <span>我是if</span>
} else {
return <span>我是else</span>
}
}
return () => (
<div>
<span v-show={
isShow}>我是v-show</span>
{
element()
}
{
isShow ? <p>我是三目1</p> : <p>我是三目2</p>
}
<div>
)
}
v-for
- Similarly, there is no
v-for
instruction , we only needmap
to use the array method of Js to render the list
template:
<ul>
<li v-for="{ id, text } in items" :key="id">
{
{ text }}
</li>
</ul>
jsx:
<ul>
{
items.value.map(({ id, text }) => {
return <li key={id}>{text}</li>
})
}
</ul>
vue3 example:
setup() {
const listData = [
{
name: 'Tom', age: 18},
{
name: 'Jim', age: 20},
{
name: 'Lucy', age: 16}
]
return () => (
<div>
<div class={
'box'}>
<span>姓名</span>
<span>年龄</span>
</div>
{
prop.listData.map(item => {
return <div class={
'box'}>
<span>{
item.name}</span>
<span>{
item.age}</span>
</div>
})
}
</div>
)
}
v-on
Those on
starting and followed by uppercase letters props
are considered event listeners. For example, equivalentonClick
to in the template .@click
<button
onClick={(event) => {
/* ... */
}}
>
click me
</button>
event modifier
For the .passive
, .capture
and .once
event modifiers, you can use camel case to splice them after the event name:
<input
onClickCapture={() => {}}
onKeyupOnce={() => {}}
onMouseoverOnceCapture={() => {}}
/>
class and style binding
There are two ways to bind class class names, using template strings or using arrays.
// 使用模板字符串两个类名之间使用空格隔开
<div className={
`header ${
isBg ? 'headerBg' : '' }`}>header</div>
//数组
<div class={
[ 'header', isBg && 'headerBg' ] } >header</div>
// style绑定需要使用 双大括号
const color = 'red'
const element = <sapn style={
{
color, fontSize: '16px' }}>style</sapn>
4. Examples of use
In development, you will encounter such a requirement: get the reference of the subcomponent and call the method defined in the subcomponent.
If a form component is encapsulated, the reference of this form component needs to be called in the parent component, and the validation form function or reset form function of this form component needs to be called. To achieve this function, first expose the function that the parent component needs to call in the child component, then go to the parent component to obtain the reference of the child component, and finally call the method exposed by the child component through the reference of the child component.
1. Subcomponent exposure method
SFC (.vue) exposed method
In the component defined by .vue, defineExpose()
the method , which can expose the internal method of the component to the parent component.
Create subcomponent demo-component-sfc.vue:
<template>
<el-button type="primary" @click="demoFun('child')">demo component sfc</el-button>
</template>
<script lang="ts" setup name="demo-component-sfc">
const demoFun = (str: string) => {
console.log('demo component sfc', str)
}
// 使用 defineExpose 暴露组件内部的方法
defineExpose({
demoFun })
</script>
TSX (.tsx) exposure method
Components defined in .tsx mode also expose component content through the expose() method in the parameter context.
Create subcomponent demo-component-tsx.tsx:
import {
defineComponent } from 'vue'
export default defineComponent({
name: 'demo-component-tsx',
setup (props, context) {
const demoFun = (str: string) => {
console.log('demo component tsx', str)
}
// 使用 expose 暴露组件内部的方法
context.expose({
demoFun })
return () => (
<el-button type="primary" onClick={
() => demoFun('child')}>demo component tsx</el-button>
)
}
})
2. The parent component calls the method in the child component
To obtain a reference to a component in .tsx, first define a ref variable, and then set the variable to the ref attribute of the child component.
import {
defineComponent, ref } from 'vue'
import DemoComponentSfc from '@/components/ref/demo-component-sfc.vue'
import DemoComponentTsx from '@/components/ref/demo-component-tsx'
export default defineComponent({
name: 'demo-ref-tsx',
setup () {
const sfcRef = ref()
const onBtnClick1 = () => {
if (sfcRef.value) {
sfcRef.value && sfcRef.value.demoFun('parent')
}
}
const tsxRef = ref()
const onBtnClick2 = () => {
if (tsxRef.value) {
tsxRef.value && tsxRef.value.demoFun('parent')
}
}
return () => (
<>
<div>
<DemoComponentSfc ref={
sfcRef} />
<el-button onClick={
onBtnClick1}>parent button</el-button>
</div>
<div style="margin-top: 10px;">
<DemoComponentTsx ref={
tsxRef} />
<el-button onClick={
onBtnClick2}>parent button</el-button>
</div>
</>
)
}
})
Remarks: <></>
In this way, the browser renders html without elements, saving a box position.
https://juejin.cn/post/7151950058501373989