React 元素的事件處理和 DOM 元素的很相似,但是有一點語法上的不同
React 事件的命名採用小駝峰式(camelCase),而不是純小寫
使用 JSX 語法時你需要傳入一個函數作為事件處理函數,而不是一個字符串
一、事件處理#
1. 事件綁定#
React 元素的事件處理和 DOM 元素類似,但是在語法上有些區別,比如:
傳統的 html:用雙引號包裹,後面必須跟參數
<button onclick="myfun()">點擊</button>
React:用大括號包裹,後面不跟參數
<button onclick={myfun}>點擊</button>
一個完整的事件函數代碼如下
class Demo extends React.Component {
render() {
// 事件函數
function myfun() {
alert('helo,world')
}
return (
// 綁定事件
<button onClick={this.myfun}>
Activate Lasers
</button>
)
}
}
ReactDOM.render(
<Demo />,
document.getElementById('root')
)
如果方法後面沒有
()
,則需要為這個方法綁定this
2. 阻止默認行為#
在 React 中還有一個不同的點,不能通過返回 fasle 阻止默認行為, React 提供了一個屬性--preventDefault
,可以通過 preventDefault 阻止腳本執行
看一下傳統的 html 和 React 的對比
<a href="#" onclick="alert('是否彈窗?');return false">
Click me
</a>
直接在寫上 false 就可以阻止腳本執行
React 通過 preventDefault 屬性阻止腳本執行:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
二、條件渲染#
在 React 中,可以創建不同的組件來封裝各種你需要的行為,然後,根據應用不同的狀態,你可以只渲染對應狀態下的部分內容。
React 中的條件渲染和 javascript 中的一樣,使用 if
運算符來表示元素當前的狀態,然後讓 React 根據他們來更新 UI。
使用 if..else 語句進行條件渲染#
先寫一個條件渲染的例子,定義了兩個組件,然後通過判斷組件 Greeting
中的變量 isLoggedIn
的真偽,讓瀏覽器渲染組件 UserGreeting
或者 GuestGreeting
。
// App.js
import React, { Component } from 'react'
export default class App extends Component {
render() {
function UserGreeting(props) {
return <h3>Welcome back!</h3>;
}
function GuestGreeting(props) {
return <h3>Please sign up.</h3>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
return (
<div>
<Greeting isLoggedIn={false} />
</div>
)
}
}
最後變量 isLoggedIn
定義了 false
,因此,瀏覽器渲染 GuestGreeting
。
怎麼阻止條件渲染?#
在有些情況下,我們希望能隱藏組件,即使他已經被其他組件渲染。我們可以通過 render
方法返回 null
讓組件不渲染。
下面的示例中, 會根據 prop 中 warn
的值來進行條件渲染。如果 warn
的值是 false
,那麼組件則不會渲染:
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
三、渲染列表#
先看一段代碼,我們使用 map()
函數讓數組中的每一項變雙倍,然後得到一個新的數組 doubled
並打印出來。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
// [2,4,6,8,10]
而在 React 中,把數組轉換為元素列表的過程是相似的。
先通過 map()
方法遍歷 numbers
數組,將數組中的每個元素變成 <li>
標籤,最後將得到的數組賦值給 listItems
。
然後返回 {listItem}
。
// Map.js
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
運行之後瀏覽器出現 1-5 的無序列表
1. 分離組件#
上面就是一個基本的列表渲染的例子,但是數據寫死了。接下來我們將數組重構成一個組件,以後再進行數組渲染時,可以輕鬆調用。
// Map.js
export default class Map extends Component {
render() {
// 分離出組件 NumberList 作為轉換數組的組件
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
// 傳入需要的數據
const numbers = [1, 2, 3, 4, 5, 6, 7];
return (
<div>
<NumberList numbers={numbers} />
</div>
)
}
}
2.key#
運行代碼之後,頁面會正常顯示,但是控制台會報一個錯誤。Each child in a list should have a unique "key" prop.
,意思是當你創建一個元素時,必須包括一個特殊的 key
屬性。
現在給每個列表元素分配一個 key:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
3. 使用 id 作為 key#
key
幫助 React 識別了哪些元素被改變,比如刪除和添加,所以應當給每個元素確定一個標識,也就是 key
。
一個元素的 key
最好是這個元素在列表中擁有的一個獨一無二的字符串。通常,我們使用數據中的 id
來作為元素的 key
:
// Map.js
export default class Map extends Component {
render() {
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.id}> // 賦值 key
{number.text}
</li>
);
return (
<ul>{listItems}</ul>
);
}
// 傳入數據
const numbers = [
{id: 1,text: 1},
{id: 2,text: 2},
{id: 3,text: 3},
{id: 4,text: 4},
{id: 5,text: 5}
];
return (
<Fragment>
<NumberList numbers={numbers} />
</Fragment>
)
}
}
4. 索引 index 可以作為 key 嗎?#
當元素沒有確定 id 的時候,萬不得已你可以使用元素索引 index
作為 key
:
const todoItems = todos.map((todo, index) =>
// 僅僅當沒有確定 id 的時候使用索引index作為 key
<li key={index}>
{todo.text}
</li>
);
如果列表項目的順序可能會變化,我們不建議使用索引來用作 key
值,因為這樣做會導致性能變差,還可能引起組件狀態的問題。
5. 用 key 提取組件#
比方說,如果你提取出一個 ListItem
組件,你應該把 key
保留在數組中的這個 <ListItem />
元素上,而不是放在 ListItem
組件中的 <li>
元素上。
錯誤的使用方法:
function ListItem(props) {
const value = props.value;
return (
// 錯誤!你不需要在這裡指定 key:
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 錯誤!元素的 key 應該在這裡指定:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
正確的使用方法:
function ListItem(props) {
// 正確!這裡不需要指定 key:
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 正確!key 應該在數組的上下文中被指定
<ListItem key={number.toString()} value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
React:一個好的經驗法則是:在 map ( ) 方法中的元素需要設置 key 屬性。
6.key 只是在兄弟節點之間必須唯一#
數組元素中使用的 key
在其兄弟節點之間應該是獨一無二的。然而,它們不需要是全局唯一的。當我們生成兩個不同的數組時,我們可以使用相同的 key
值:
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
7.vue 中渲染列表#
Vue 中渲染列表使用的是特殊指令 v-for
,其中也有 key
的相關用法
React 中採用的是 map()
方法遍歷數組,然後渲染列表