react - 条件渲染,列表渲染,表单绑定,状态提升

本文介绍了React中条件渲染的几种方式,包括使用&&、三元运算符以及动态className和style。接着讲解了列表渲染的最佳实践,强调了key的重要性。在表单绑定部分,阐述了受控组件的概念和使用。最后,探讨了状态提升,即如何在父子组件间共享状态,以及在同级组件间通过父组件进行状态提升的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

九、条件渲染

在 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>
    )
  }
}

补充:

  • css-in-js

    $ cnpm i styled-components -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' // 条件判断 样式
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>
    );
  }
}
  • 模块化css

可以解决类似于 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

使用 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="🏀" onChange={ this.handlerHobbyChange.bind(this) }/>🏀
          <input type="checkbox" name="hobby" value="⚽" onChange={ this.handlerHobbyChange.bind(this) }/>⚽
          <input type="checkbox" name="hobby" value="🏐" onChange={ this.handlerHobbyChange.bind(this) }/>🏐
          <input type="checkbox" name="hobby" value="🏓" onChange={ this.handlerHobbyChange.bind(this) }/>🏓 
          --- 
          { 
            this.state.hobby && this.state.hobby.map(item => {
              return <span key = { item }>{item}</span>
            }) 
          }
        </div>
        <div>
          <select name="lesson" value = { this.state.lesson } onChange = { this.changeVal.bind(this) }>
            <option value="一阶段">一阶段</option>
            <option value="二阶段">二阶段</option>
            <option value="三阶段">三阶段</option>
          </select>
           ---- { this.state.lesson }
        </div>
        <div >
          <textarea name="note" value={this.state.note} onChange = { this.changeVal.bind(this) }/>{ this.state.note }
        </div>
        <div >
          <input type="checkbox" name="flag" value={ this.state.flag } onChange= { (event) => {
            this.setState({
              flag: event.target.checked
            })
          }} /> 同意 **** 协议 { this.state.flag }
        </div>
        <button onClick={() => {
          console.log({
            userName: this.state.userName,
            password: this.state.password,
            sex: this.state.sex,
            hobby: this.state.hobby,
            lesson: this.state.lesson,
            note: this.state.note,
            flag: this.state.flag
          })
        }}>获取数据</button>
      </div>
    );
  }
}

11.2 受控表单以及受控组件

在 HTML 中,表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

inputtextareaselect 受控组件: value的属性受了 state 的控制

  • 使用了受控组件,一定要写 value 属性以及onChange事件

radio、‘checkbox’ 受控组件: checked 的属性受了state的控制

如果需要设置默认值,那么需要通过 defaultValue 以及defaultChecked设置

案例如上

十二、状态提升

在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的“状态提升”。

12.1 父子组件通信

src/index.js

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'

// 引入react组件时,后缀名可以不写
import App from './07_state_up/01_App-parent-child-value'

const root = ReactDOM.createRoot(document.querySelector('#root'))

root.render(<App />)

src/07_state_up/01_App-parent-child-value.jsx

// src/07_state_up/07_state_up/01_App-parent-child-value.jsx
import React, { Component } from 'react'

class Child1 extends Component {
  state = { count: 1 }
  render () {
    return (
      <>
        <h1>child1组件</h1>
        { this.state.count }
        <button onClick={ () => { this.setState({count: this.state.count + 1} ) }}>加1</button>
      </>
    )
  }
}
class Child2 extends Component {
  state = { count: 1 }
  render () {
    return (
      <>
        <h1>child2组件</h1>
        { this.state.count }
        <button onClick={ () => { this.setState({count: this.state.count + 1} ) }}>加1</button>
      </>
    )
  }
}
class App extends Component {
  render() {
    return (
      <div>
        <Child1 ></Child1>
        <hr></hr>
        <Child2 ></Child2>
      </div>
    );
  }
}

export default App;

我们发现Child1和Child2都是两个独立的个体,并没有实现数据共享

src/index.js

// src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'

// 引入react组件时,后缀名可以不写
// import App from './07_state_up/01_App-parent-child-value'
import App from './07_state_up/02_App_state_up'

const root = ReactDOM.createRoot(document.querySelector('#root'))

root.render(<App />)

src/07_state_up/02_App_state_up.jsx

// src/07_state_up/07_state_up/02_App_state_up.jsx
import React, { Component } from 'react'

class Child1 extends Component {
  // state = { count: 1 }
  render () {
    return (
      <>
        <h1>child1组件</h1>
        { this.props.count }
        <button onClick={ () => { this.props.onClick() }}>加1</button>
      </>
    )
  }
}
class Child2 extends Component {
  // state = { count: 1 }
  render () {
    return (
      <>
        <h1>child2组件</h1>
        { this.props.count }
        <button onClick={ () => { this.props.onClick() }}>加1</button>
      </>
    )
  }
}
class App extends Component {
  state = {
    count: 1
  }
  add = () => {
    this.setState({ count: this.state.count + 1 })
  }
  render() {
    return (
      <div>
        <Child1 count = { this.state.count } onClick = { this.add }></Child1>
        <hr></hr>
        <Child2 count = { this.state.count } onClick = { this.add }></Child2>
      </div>
    );
  }
}

export default App;

12.2 状态提升解读

实现方式是 利用最近的共同的父级组件中,用props的方式传过去到两个子组件,props中传的是一个setState的方法,通过子组件触发props传过去的方法,进而调用父级组件的setState的方法,改变了父级组件的state,调用父级组件的add方法,进而同时改变了两个子级组件的数据

这是 两个有关连的同级组件的传值,因为react的单项数据流,所以不在两个组件中进行传值,而是提升到 最近的共同的父级组件中,改变父级的state,进而影响了两个子级组件的render

注意如果两个组件是同级组件(这两个组件的父组件是同一个)才考虑状态提升共享数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值