React:JSX 是什麼?為何在 React 中使用 JSX?
3.6k 字,約 4 分鐘
文章目錄
什麼是 JSX? 為什麼要用JSX?
- JSX(JavaScript XML)是一種 JavaScript 的語法擴展,通常與 React 一同使用。它允許開發者在 JavaScript 中使用類似 XML 或 HTML 的語法來撰寫 React 元素,並透過渲染(Render)將其轉譯為實際的 DOM 元素及相對應的事件。這種語法使得 React 組件的描述更直觀、易讀,同時提供了更高效的元素創建方式。
- JSX只是為React element(原生語法)提供語法糖。
- 原生創建React元素語法:React.createElement(component, props, ...children)。
- component:React 元素的類型,可以是 HTML 元素名稱(字符串,例如 'div')或 React 組件
- props:元素的屬性(attributes),是一個包含元素屬性及其值的物件。
- ...children:元素的子元素,可以是單一元素或一個包含多個子元素的數組。
React.createElement(
div,
{className: 'info'},
'Hello World'
)
- JSX寫法如下
<div className="info">Hello World</div>
- 巢狀寫法的案例如下:
- React.createElement寫法
React.createElement(
'div',
{ className: 'container' },
React.createElement(
'h1',
null,
'Nested Example'
),
React.createElement(
'p',
{ style: { color: 'blue' } },
'This is a nested paragraph.'
)
);
- JSX寫法
<div className="container">
<h1>Nested Example</h1>
<p style={{ color: 'blue' }}>This is a nested paragraph.</p>
</div>
JSX內部原理及規則
- JSX會在編譯階段被轉譯成對應的 React.createElement 的呼叫,生成一個 JavaScript 物件,這個物件描述了 React 元素的類型、屬性(props),以及子元素。
JSX使用規則如下
使用者定義的元件必須大寫
- 錯誤寫法
import React from 'react';
// ↓ 正確:hello->Hello
function hello(props) {
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// ↓ 使用hello非大寫會導致發生錯誤,無法透過JSX引用該元件
// 正確的方式:hello->Hello
return <hello toWhat="World" />;
}
- 正確寫法
import React from 'react';
function Hello(props) {
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
return <Hello toWhat="World" />;
}
React元件不能使用表達式(只能是大寫字母開頭的變數或函數名)
- 錯誤寫法
import React from 'react';
// PhotoStory 元件
function PhotoStory(props) {
return <div>Photo Story: {props.story}</div>;
}
// VideoStory 元件
function VideoStory(props) {
return <div>Video Story: {props.story}</div>;
}
// Story 元件
const Components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// ↓ 請用變數賦值,避免使用表達式
return <Components[props.storyType]; story={props.story} />;
}
// App 元件
function App() {
return (
<div>
<Story storyType="photo" story="A beautiful photo story" />
<Story storyType="video" story="An amazing video story" />
</div>
);
}
export default App;
- 正確寫法
- CodePen連結
import React from 'react';
// PhotoStory 元件
function PhotoStory(props) {
return <div>Photo Story: {props.story}</div>;
}
// VideoStory 元件
function VideoStory(props) {
return <div>Video Story: {props.story}</div>;
}
// Story 元件
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 根據 props 中的 storyType 選擇要渲染的元件
const SpecificStory = components[props.storyType];
// 渲染所選擇的元件,並將 story 作為 props 傳遞
return <SpecificStory story={props.story} />;
}
// App 元件
function App() {
return (
<div>
<Story storyType="photo" story="A beautiful photo story" />
<Story storyType="video" story="An amazing video story" />
</div>
);
}
export default App;
顯示如下:
Photo Story: A beautiful photo story
Video Story: An amazing video story
回傳單一個根元素
- 最外層需要使用父層元素包覆(EX:div、或使用 Fragment (<> 和 </>))
- 案例如下:
import React from 'react';
function App() {
return (
<>
<div>Content 1</div>
<div>Content 2</div>
</>
);
}
所有標籤都需要結尾標籤
範例如下:
<div></div>
- 自閉標籤(self-closing)範例如下
<img />
JSX特色
Props可以使用Javascript表達式(foo={1 + 2 + 3 + 4})
- Javascript表達式案例如下:
- Codepen連結
function MyComponent(props) {
return <div>由App組件傳過來的foo參數:{props.foo}</div>
}
function App() {
return (
<div>
<MyComponent foo={1 + 2 + 3 + 4} />
</div>
);
}
export default App;
顯示如下:
由App組件傳過來的foo參數:10
- if跟for不是表達式不能使用
- 三元運算符(肚子餓了嗎?餓了:還沒餓)及邏輯運算符(&&)算是表達式的一種
- 三元運算符案例如下:
- Codepen連結
import React, { useState } from 'react';
const Greeting = ({ isLoggedIn }) => {
return (
<div>
{isLoggedIn ? (
<p>Welcome back!</p>
) : (
<p>Please log in.</p>
)}
</div>
);
};
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const handleLoginToggle = () => {
setIsLoggedIn((prevIsLoggedIn) => !prevIsLoggedIn);
};
return (
<div>
<button onClick={handleLoginToggle}>
{isLoggedIn ? 'Logout' : 'Login'}
</button>
<Greeting isLoggedIn={isLoggedIn} />
</div>
);
};
export default App;
- 邏輯運算符(&&)案例如下:
- Codepen連結
import React, { useState } from 'react';
const App = () => {
const isLoggedIn = true
return (
<div>
{isLoggedIn && <p>Welcome back!</p>}
</div>
);
};
export default App;
顯示如下:
Welcome back!
純布林值、Null 和未定義值將被忽略(以下案例全部均顯示空白)
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
屬性展開(...)
const App = () => {
const props = { className: 'my-class', style: { color: 'red' } };
return (
<div>
<div {...props}>Hello, World!</div>
</div>
);
};
export default App;
陣列作為子元素: 你可以使用陣列來傳遞多個子元素
import React, { useState } from 'react';
const App = () => {
const items = ['Item 1', 'Item 2', 'Item 3'];
return (
<div>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
};
export default App;
React內聯樣式(inline styles)
- JSX不能使用保留字(會自動轉換成別的字詞避免與保留字衝突)
- class->className
- for->htmlfor(label)
- CSS內聯屬性stroke-width改成駝峰式命名(Camel-Case)strokeWidth
const App = () => {
return (
<div>
<div style={{ color: 'red', fontSize: '16px' }}>Hello, World!</div>
</div>
);
};
留言
留言使用 GitHub 帳號登入(Giscus),留言會存在 GitHub Discussions。