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
让组件不渲染。
下面的示例中,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()
方法遍历数组,然后渲染列表
title: React 学习笔记(二) date: 2020-12-16 13:15:00 updated: 2021-11-09 15:19:31 categories:
- 技术 tags:
- react
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
让组件不渲染。
下面的示例中,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()
方法遍历数组,然后渲染列表