目录:
1. Props 概念
3. 列表渲染
4. 条件渲染
什么是 props
当 React 元素作为自定义组件,将 JSX 所接受的属性转换为单个对象传递给组件,这个对象被称为“props”。
更简单的理解是,props 是父组件传递给子组件的一个参数对象。
从字面意思上来看,props 是 properties 的缩写,就是属性的意思。
props 有哪些规则跟属性
props 是组件的固有属性,它是通过 JSX 标签传递给子组件的。
不可在组件内部对 props 进行修改。
如果需要更新 props,需要通过父组件重新传入新的 props ,更新子组件。从这个意义上来讲,React 是单向数据流,props 就是从父组件传向子组件的数据。
类组件对 props 的传递
下面举例,实现将父组件中定义的商品信息传递给子组件并进行渲染。listItem.jsx 是 App.js 的子组件。
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <title>React App</title> </head> <body> <div id="root"></div> </body> </html>
index.js(React入口文件):
导入 App.js,在页面上渲染 App 组件。
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import 'bootstrap/dist/css/bootstrap.css'; ReactDOM.render( <App />, document.getElementById('root'));
App.js:
注册引用子组件 listItem.jsx。创建一个 listData 数组,将 props 命名为 data,通过 data 将定义好的数据传递给子组件,这里传递了 listData[0] 跟 listDate[1]。
import React from 'react'; import ListItem from './components/listItem' const listDate = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] function App() { return( <div className="container"> <ListItem data={ listDate[0] } /> <ListItem data={ listDate[1] } /> </div> ) } export default App;
listItem.jsx:
创建一个 constructor 方法,将 props 作为参数传入,调用 super 方法,因为 JS 强制规定子类的构造函数必须先调用一次 super 函数。然后将 props 的数据加载到元素上。
import React, { Component } from 'react'; class ListItem extends Component { constructor( props ){ super(props) } render() { return ( <div className="row"> <div className="col-2">{this.props.data.id}</div> <div className="col-2">{this.props.data.name}</div> </div> ); } } export default ListItem;
页面表现:
函数组件对 props 的传递
下面举例,实现跟上面例子相同的效果。
index.js (React入口文件):
导入 App.js,在页面上渲染 App 组件。
App.js :
注册引用子组件 listItemFunc.jsx
import React from 'react'; import ListItem from './components/listItemFunc' const listDate = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] function App() { return( <div className="container"> <ListItem data={ listDate[0] } /> <ListItem data={ listDate[1] } /> </div> ) } export default App;
listItemFunc.jsx:
import React from 'react'; const ListItem = (props) => { return ( <div className="row"> <div className="col-2">{props.data.id}</div> <div className="col-2">{props.data.name}</div> </div> ); } export default ListItem;
需要在函数组件引入 React,因为不管是函数组件还是类组件都会通过 Babel 来转换为浏览器执行的代码。
如果有下载 Simple React Snippets 插件,可以使用 sfc 缩写快速创建函数组件。
定义一个 ListItem 函数,props 作为参数传入。
函数组件没有 this 关键字,也就是说,需要将 this.props 替换为 props。
函数组件与类组件的其中一个区别是,函数组件的 props 是直接通过函数参数的形式传递的。
页面表现:
函数组件要素
● 函数组件也叫无状态组件
● 组件内部没有 this (组件实例)
● 没有生命周期
(有 React Hook 在函数组件中也可以使用状态以及生命周期)
函数组件的优点:比较轻量。如果组件没有涉及状态,只是用于渲染数据的话,那么可以使用函数组件,这样可以拥有更好的性能,它就是一个纯函数,当有相同的输入时就会有相同的输出,没有任何副作用。
React 的 JSX 不是模板引擎,所以,需要通过 JS 的表达式形式来达到相应的需求。React 使用 map 方法实现列表渲染。
例子
index.js(React入口文件):
导入 App.js,在页面上渲染 App 组件。
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import 'bootstrap/dist/css/bootstrap.css'; ReactDOM.render( <App />, document.getElementById('root'));
App.js:
注册引用子组件 listItem.jsx。创建一个 listData 数组。
使用 map 方法进行列表渲染,在 listData 数组上使用 map 方法,参数里的函数会作用于数组中的每一个元素,函数的参数 item 是指遍历到的当前元素,函数返回子组件<ListItem>,将 item 作为 props 赋给每一个子元素。
每一个列表都需要有一个 key 属性值,因为 React 必须知道每个元素的独立标识,key 帮助识别哪些元素改变了(比如说被添加/删除了),React 需要快速地知道虚拟 DOM 哪里发生了变化而快速地找到真实 DOM。因此,在做列表渲染的时候,特别是数据量相当庞大的时候,应当给数组中的每一个元素赋予一个确定的标识。下面例子中将商品的 id 赋予给 key。属性 key 不会渲染在 DOM 上,key 只是给 React 内部做一个标识的认定。数组元素的 key 在其兄弟节点之间要是独一无二的。
import React from 'react'; import ListItem from './components/listItem' const listData = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] function App() { return( <div className="container"> {listData.map( item => { return <ListItem key={item.id} data={ item }/> })} </div> ) } export default App;
listItem.jsx:
传入 props,引用 props
import React, { Component } from 'react'; class ListItem extends Component { constructor( props ){ super(props); this.state = {};//不加这条语句会报错//暂时不懂为什么 } render() { return ( <div className="row"> <div className="col-2">{this.props.data.id}</div> <div className="col-2">{this.props.data.name}</div> </div> ); } } export default ListItem;
React 的 JSX 不是模板引擎,所以,需要通过 JS 的表达式形式来达到相应的需求。条件渲染的方法比列表渲染的方法多,下面介绍 3 中常用的方法。
1. 使用三目运算符( boolean ? case1 : case2 )
2. 使用函数做条件判断
3. 使用与运算符 && 判断
使用三目运算符( boolean ? case1 : case2 )
例 子
实现用三目运算符判断样式。在 index.css 里定义样式 themed-grid-col 跟 themed-grid-col-s ,在 listItem.jsx 中使用三目运算符进行判断,如果 count 为 0 则用样式 themed-grid-col-s,否则用样式 themed-grid-col。
index.js(React入口文件):
导入 App.js,在页面上渲染 App 组件。
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css' import App from './App'; import 'bootstrap/dist/css/bootstrap.css'; ReactDOM.render( <App />, document.getElementById('root'));
App.js:
注册引用子组件 listItem.jsx。
import React from 'react'; import ListItem from './components/listItem' const listData = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] function App() { return( <div className="container"> {listData.map( item => { return <ListItem key={item.id} data={ item }/> })} </div> ) } export default App;
index.css:
存放样式,在 listItem.jsx 中会用到样式 themed-grid-col 跟 themed-grid-col-s。
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.themed-grid-col {
padding-top: 15px;
padding-bottom: 15px;
background-color: rgba(255, 255, 255);
border: 1px solid rgba(86, 61, 124, 0.2);
}
.themed-grid-col-s {
padding-top: 15px;
padding-bottom: 15px;
background-color: rgba(86, 61, 124, 0.2);
border: 1px solid rgba(86, 61, 124, 0.2);
}
listItem.jsx:
import React, { Component } from 'react'; let count = 0; class ListItem extends Component { constructor( props ){ super(props); this.state = {};//不加这条语句会报错//暂时不懂为什么 } render() { return ( <div className="row mb-3"> <div className="col-2 themed-grid-col">{this.props.data.id}</div> <div className="col-6 themed-grid-col"> <span> {this.props.data.name} </span> </div> <div className={"col-2 themed-grid-col" + (count ? '' : '-s')}> {count} </div> </div> ); } } export default ListItem;
( 第 19 行可以用 es6 语法写,可以改成 )
页面表现:
因为 count 是 0 , 所以样式是 themed-grid-col-s (背景颜色为灰色)。
例 子
在前面例子的基础上,在 App.js 中使用函数 renderList 做一个条件判断。如果 listData 为空数组,则返回提示”购物车是空的“,如果不为空,则正常返回 React 元素。在 render 表达式里直接调用 this.renderList() 。
import React, { Component } from 'react'; import ListItem from './components/listItem' const listData = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] class App extends Component { renderList(){ if(listData.length === 0){ return <div className="text-center">购物车是空的</div> } return listData.map( item => { return <ListItem key={item.id} data={ item }/> }) } render() { return( <div className="container"> { this.renderList() } </div> ) } } export default App;
页面表现:
listData 为空数组时:
listData 不为空数组时:
使用与运算符 && 判断
例 子
在上面使用函数做条件判断的例子的基础上,修改 App.js。
与运算符 && 最基本的使用方法是:当 && 前后的表达式都是 true,就会返回 true,否则返回 false。在这个例子中使用 && 判断的原理是:&& 的前面如果是 false,会直接返回 false/空字符串/零/null/undefined。如果 && 前面是 true,那么会返回 && 后面的表达式。在本例中,当 && 前面的“ listData.length === 0 ”为 true,会返回 && 后面的React元素 “ <div className="text-center"> 购物车是空的</div>”。
本例中使用 && 判断的语句是:
import React, { Component } from 'react'; import ListItem from './components/listItem' const listData = [ { id: 1, name: '红苹果', }, { id: 2, name: '青苹果', }, ] class App extends Component { renderList(){ return listData.map( item => { return <ListItem key={item.id} data={ item }/> }) } render() { return( <div className="container"> { listData.length === 0 && <div className="text-center">购物车是空的</div> } { this.renderList() } </div> ) } } export default App;
页面表现:
listData 为空时:
listData 不为空时: