九、条件渲染
在 React 中,你可以创建不同的组件来封装各种你需要的行为。然后还可以根据应用的状态变化只渲染其中的一部分。
React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。
9.1 &&
你可以通过用花括号包裹代码在 JSX 中嵌入任何表达式 ,也包括 JavaScript 的逻辑与 &&,它可以方便地条件渲染一个元素。
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
import App from './04_condition/01_App_condition_yu' // 条件判断与
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/01_App_condition_yu.jsx
// src/04_condition/01_App_condition_yu.jsx
import React, { Component } from 'react';
class MailBox extends Component {
render () {
return (
<div>
{
this.props.unReadMessage.length > 0 && <div>还有{this.props.unReadMessage.length}未读邮件</div>
}
</div>
)
}
}
export default class App extends Component {
state = {
messageList: ['a', 'b', 'c', 'd']
}
render() {
return (
<div>
{
// 如果messageList从服务器获取, 初始数据为空数组,其实没有必要 map 遍历
this.state.messageList && this.state.messageList.map((item, index) => {
return (
<p key={ index }>
{ item }
<button onClick={
() => {
// 获取数据
const arr = this.state.messageList
// 处理数据
arr.splice(index, 1)
// 修改状态
this.setState({
messageList: arr
})
}
}>阅读</button>
</p>
)
})
}
<MailBox unReadMessage = { this.state.messageList }/>
</div>
);
}
}
9.2 三元运算符
条件渲染的另一种方法是使用 JavaScript 的条件运算符:
condition ? true : false。
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
// import App from './04_condition/01_App_condition_yu' // 条件判断与
import App from './04_condition/02_App_condition_san' // 条件判断 三元运算符
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/02_App_condition_san.jsx
// src/04_condition/02_App_condition_san.jsx
// 在jsx 中不要使用 if 以及 for 等流程控制语句
// 可以在 if 条件语句中 返回 jsx代码
import React, { Component } from 'react';
export default class App extends Component {
state = {
loginState: false
}
// 1.三元运算符
// render () {
// return (
// <div>
// { this.state.loginState ? '登录了' : '未登录' }
// <button onClick={ () => {
// this.setState({
// loginState: !this.state.loginState
// })
// }}>切换</button>
// </div>
// )
// }
// render () {
// if (this.state.loginState) {
// return (
// <div>
// 登录了
// <button onClick={ () => {
// this.setState({
// loginState: !this.state.loginState
// })
// }}>切换</button>
// </div>
// )
// } else {
// return (
// <div>
// 未登录
// <button onClick={ () => {
// this.setState({
// loginState: !this.state.loginState
// })
// }}>切换</button>
// </div>
// )
// }
// }
render () {
const HTML = <button onClick={ () => {
this.setState({
loginState: !this.state.loginState
})
}}>切换</button>
if (this.state.loginState) {
return (
<div>
登录了 { HTML }
</div>
)
} else {
return (
<div>
未登录 { HTML }
</div>
)
}
}
}
9.3 动态className
Vue中有很方便的动态绑定class属性的方式,v-bind:class,那么react怎么实现这样的效果呢?
<button class="btn btn-success btn-sm"></button>
<button class="btn btn-danger btn-sm"></button>
<button class="btn btn-warning btn-sm"></button>
{ this.state.type === 'success' ? 'btn btn-success btn-sm' : 'btn btn-sm'}
通过classnames这个插件可以实现
$ cnpm i classnames -S
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
// import App from './04_condition/01_App_condition_yu' // 条件判断与
// import App from './04_condition/02_App_condition_san' // 条件判断 三元运算符
import App from './04_condition/03_App_condition_classname' // 条件判断 样式
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/03_App_condition_classname.jsx
// src/04_condition/03_App_condition_classname.jsx
import React, { Component } from 'react'
import classnames from 'classnames'
export default class App extends Component {
state = {
type: 'default', // success danger warning default
size: 'md' // sm md lg (小 中 大)
}
render() {
return (
<div>
<button onClick={ () => this.setState({ type: 'success' })}>success</button>
<button onClick={ () => this.setState({ type: 'danger' })}>danger</button>
<button onClick={ () => this.setState({ type: 'warning' })}>warning</button>
<button onClick={ () => this.setState({ type: 'default' })}>default</button>
<button onClick={ () => this.setState({ size: 'sm' })}>sm</button>
<button onClick={ () => this.setState({ size: 'md' })}>md</button>
<button onClick={ () => this.setState({ size: 'lg' })}>lg</button>
<button className={
classnames({
btn: true,
'btn-success': this.state.type === 'success',
'btn-sm': this.state.size === 'sm'
})
}>success小号按钮</button>
<button className={ (this.state.type === 'success' && this.state.size === 'sm') ? 'btn btn-success btn-sm' : (this.state.type === 'success' && this.state.size !== 'sm') ? 'btn btn-success' : (this.state.type !== 'success' && this.state.size === 'sm') ? 'btn btn-sm' : 'btn'}>success小号按钮</button>
</div>
)
}
}
补充:
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
// import App from './04_condition/01_App_condition_yu' // 条件判断与
// import App from './04_condition/02_App_condition_san' // 条件判断 三元运算符
// import App from './04_condition/03_App_condition_classname' // 条件判断 样式
import App from './04_condition/04_App_condition_cssinjs' // css in js
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/04_App_condition_cssinjs.jsx
// src/04_condition/04_App_condition_cssinjs.jsx
import styled from 'styled-components'
import React, { Component } from 'react';
// css in js
const Button = styled.button`
padding: 30px;
font-size: 20px;
`
export default class App extends Component {
render() {
return (
<div>
<Button>按钮</Button>
</div>
);
}
}
可以解决类似于 vue中 scoped
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
// import App from './04_condition/01_App_condition_yu' // 条件判断与
// import App from './04_condition/02_App_condition_san' // 条件判断 三元运算符
// import App from './04_condition/03_App_condition_classname' // 条件判断 样式
// import App from './04_condition/04_App_condition_cssinjs' // css in js
import App from './04_condition/05_App_module_css' // 模块化css
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/05_App_module_css.jsx
// src/04_condition/05_App_module_css.jsx
import './style.css'
// 模块化css
import style from './style.module.css'
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
// <div className="container">
// <header className="header"></header>
// <div className="content"></div>
// <footer className="footer"></footer>
// </div>
<div className={ style.container }>
<header className={ style.header}></header>
<div className={ style.content}></div>
<footer className={ style.footer}></footer>
</div>
);
}
}
src/04_condition/style.module.css
* {padding: 0; margin: 0;}
html, body{ height: 100%;}
#root { height: 1000px;}
.container {
width: 100%;
height: 600px;
display: flex;
flex-direction: column;
}
.header {
height: 100px;
background-color: #f66;
}
.content {
flex: 1;
}
.footer {
height: 100px;
background-color: #ccc;
}
9.4 动态style
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './01_props/01_Parent_Child' // 父子组件
// import App from './01_props/02_Parent_Child_value' // 父组件给子组件传值
// import App from './01_props/03_Parent_Child_default' // 父组件给子组件传值,子组件设置默认值
// import App from './01_props/04_Parent-Child_type' // 父组件给子组件传值,子组件设置默认值,验证数据类型
// import App from './01_props/05_App_props_children' // 类插槽
// import App from './01_props/06_App_mutiple_props_children' // 类具名插槽 多个插槽
// import App from './01_props/07_App_mouse_tracker' // 鼠标跟随
// import App from './01_props/08_App_render_props' // 渲染属性 - 其他组件共享状态
// import App from './02_state/01_App_state_es6' // 初始化状态 - es6的构造函数
// import App from './02_state/02_App_state_es7' // 初始化状态 - es7 属性初始化器
// import App from './02_state/03_App_setState_function' // 修改状态 传递函数
// import App from './02_state/04_App_setState_object' // 修改状态 传递对象
// import App from './02_state/05_App_computed' // 类组件实现类似于vue的计算属性
// import App from './02_state/06_App_lifeCycle' // 生命周期
// import App from './03_event/01_App_event_es5' // es5事件绑定
// import App from './03_event/02_App_event_es6' // es6事件绑定
// import App from './04_condition/01_App_condition_yu' // 条件判断与
// import App from './04_condition/02_App_condition_san' // 条件判断 三元运算符
// import App from './04_condition/03_App_condition_classname' // 条件判断 样式
// import App from './04_condition/04_App_condition_cssinjs' // css in js
// import App from './04_condition/05_App_module_css' // 模块化css
import App from './04_condition/06_App_style' // 动态style
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/04_condition/06_App_style.jsx
// src/04_condition/06_App_style.jsx
import React, { Component } from 'react'
// style 小驼峰式 单位可省略
export default class App extends Component {
state = {
size: 12,
color: '#000'
}
render() {
// <></> 空标签
return (
<>
<input type="color" value={ this.state.color } onChange = { event => this.setState({ color: event.target.value })} />
<button onClick={ () => this.setState({ size: this.state.size + 2 })}>加</button>
<button onClick={ () => this.setState({ size: this.state.size - 2 })}>减</button>
<div style={ { fontSize: this.state.size + 'px', color: this.state.color } }>
自从去年中国决定逐渐放松防疫限制之后,中国疫情成为全球关注的焦点,引起诸多外国媒体的好奇。近日,《纽约时报》发布报道称:“早有预见中国的新冠清零会结束,但是从来没有想过会以这样的方式结束。”
</div>
</>
)
}
}
十、列表渲染
使用 map() 方法遍历数组
组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key:
Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的id
作为元素的 key
当元素没有确定的 id 时,你可以使用他的序列号索引 index
作为 key
如果列表可以重新排序,我们不建议使用索引来进行排序,因为这会导致渲染变得很慢。
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
import App from './05_list/01_App_map'
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/05_list/01_App_map.jsx
// src/05_list/01_App_map.jsx
// React中使用 map 来遍历数据,需要 添加唯一值key
import React, { Component } from 'react'
export default class App extends Component {
state = {
list: ['aa', 'bb', 'cc', 'dd']
}
// 边遍历边渲染
// render() {
// return (
// <div>
// {
// this.state.list && this.state.list.map((item, index) => {
// return (
// <div key = { index }>{ item }</div>
// )
// })
// }
// </div>
// )
// }
// 先遍历后渲染
render () {
const arr = []
this.state.list.forEach((item, index) => {
arr.push(<div key = { index }>{ item }</div>)
})
return (
<div>
{ arr }
</div>
)
}
}
接口 http://121.89.205.189:3000/api/city/sortCity
实现多层遍历
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
// import App from './05_list/01_App_map'
import App from './05_list/02_App_mutiple_map'
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/05_list/02_App_mutiple_map.jsx
// src/05_list/02_App_mutiple_map.jsx
// React中使用 map 来遍历数据,需要 添加唯一值key
import React, { Component } from 'react'
export default class App extends Component {
state = {
list: ['aa', 'bb', 'cc', 'dd'],
newList: [
{
brand: '宝马',
data: ['X5', 'X7']
},
{
brand: '奥迪',
data: ['Q3', 'RS7']
}
]
}
// 边遍历边渲染
// render() {
// return (
// <div>
// {
// this.state.list && this.state.list.map((item, index) => {
// return (
// <div key = { index }>{ item }</div>
// )
// })
// }
// {
// this.state.newList && this.state.newList.map(item => {
// return (
// <div key = { item.brand }>
// {
// item.brand
// }
// {
// item.data.map((itm, idx) => {
// return <p key = { idx }> { itm }</p>
// })
// }
// </div>
// )
// })
// }
// </div>
// )
// }
// 先遍历后渲染
render () {
const arr = []
this.state.list.forEach((item, index) => {
arr.push(<div key = { index }>{ item }</div>)
})
const newArr = []
this.state.newList.forEach(item => {
const newData = []
item.data.forEach((itm,idx) => {
newData.push(<p key = { idx }>{ itm }</p>)
})
newArr.push(<div key = { item.brand }>{ item.brand } - { newData }</div>)
})
return (
<div>
{ arr }
{ newArr }
</div>
)
}
}
十一、表单绑定
在 React 里,HTML 表单元素的工作方式和其他的 DOM 元素有些不同,这是因为表单元素通常会保持一些内部的 state。例如这个纯 HTML 表单只接受一个名称:
<form>
<label>
名字:
<input type="text" name="name" />
</label>
<input type="submit" value="提交" />
</form>
此表单具有默认的 HTML 表单行为,即在用户提交表单后浏览到新页面。如果你在 React 中执行相同的代码,它依然有效。但大多数情况下,使用 JavaScript 函数可以很方便的处理表单的提交, 同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用“受控组件”。
表单元素的value值受 state的控制
11.1 各种表单的绑定与取值
src/index.js
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
// 引入react组件时,后缀名可以不写
import App from './06_form/01_App_form'
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App />)
src/06_form/01_App_form.jsx
// src/06_form/01_App_form.jsx
import React, { Component } from 'react';
export default class App extends Component {
state = {
userName: '',
password: '',
sex: '',
hobby: [],
lesson: '',
note: '',
flag: false
}
changeVal (event) {
console.log(event)
// this.setState({
// userName: event.target.value
// })
this.setState({
[event.target.name]: event.target.value
})
}
handlerHobbyChange (event) {
console.log(event.target.checked)
const checked = event.target.checked
const value = event.target.value
const arr = this.state.hobby
if (checked) {
arr.push(value)
} else {
const index = arr.findIndex((item) => {
return item === value
})
arr.splice(index, 1)
}
console.log('22', arr)
this.setState({
hobby: arr
})
}
render() {
return (
<div>
<div>
<input type="text" name="userName" value = { this.state.userName } onChange = { this.changeVal.bind(this) }/>
{ this.state.userName }
</div>
<div>
<input type="password" name="password" value = { this.state.password } onChange = { this.changeVal.bind(this) }/>
{ this.state.password }
</div>
<div>
<input type="radio" name="sex" value = '男' onChange={ this.changeVal.bind(this) }/>男
<input type="radio" name="sex" value = '女' onChange={ this.changeVal.bind(this) }/>女
---- { this.state.sex }
</div>
<div>
<input type="checkbox" name="hobby" value="
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)