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() 方法遍历数组,然后渲染列表 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 让组件不渲染。 下面的示例中, 会根据 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() 方法遍历数组,然后渲染列表