React基础学习-1

1.React概述

1.1React简介

  • React 是一个 MVC 框架
  • React 主要是用来构建 UI
  • React 是起源于Facebook的内部项目,用于构建 Instagram 网站,在 2013.05 开源

React 特点:

  • 声明式:使用 React 编写UI界面和写HTML几乎一样
  • 高效: React通过对DOM的模拟,最大限度地减少与DOM的交互
  • 灵活:React可以与已知的库或框架很好地配合

1.2 项目搭建

# 创建 react 项目,项目名是 myapp
npx create-react-app myapp

# 进入my-app 目录
cd myapp

# 启动项目
npm start

注意事项:

  • 项目名称中不能有大写字母

  • npx 是 npm v5.2.0 之后提供的命令,使用npx后不需要先全局安装脚手架

  • 要在项目根目录下启动项目

1.3项目结构说明

项目结构说明
修改项目端口号:在 package.json 文件中修改 scripts 节点

修改项目端口号

1.4 React 基本使用

  • 导入 react 和 react-dom 两个包
  • 使用 JSX 语法创建 react 元素
  • 调用 ReactDOM.render() 方法将元素渲染到页面中

index.js 文件

// 1. 导入 react 和 react-dom 两个包
import React from 'react'
import ReactDOM from 'react-dom'

// 2. 创建 react 元素
const jsx =<h1>Hello World</h1>// 3. 调用 ReactDOM.render() 方法将元素渲染到页面中
// 参数1: react元素
// 参数2: html 页面中的 DOM 元素
ReactDOM.render(jsx, document.querySelector('#app'))

index.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

2. JSX

2.1 JSX简介

JSX 是 JavaScript XML 的简写,就是在 JavaScript 中写 XML 格式的代码(目前我只需要写 HTML)

优势: 和 HTML 一样,简单直观

注意点: 使用小括号包裹 JSX,避免 JS 格式化时自动插入分号

const jsx = (
  <div>
    <h1>用户信息</h1>
    <ul>
      <li>用户名: admin</li>     
      <li>密码: 123456</li>     
    </ul>
  </div>
)

2.2 JSX中的表达式

在 JSX 中,可以在 { } 中嵌入表达式

  • 变量 (除了对象都可以)
  • 算数表达式
  • 函数表达式
  • jsx自身也能作为表达式

不能出现在 { } 中的东西

  • 变量中保存了一个对象 (只有 style 中可以使用对象)
  • if/for 等流程控制不能出现在 { } 中
import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 掌握 { } 中能使用哪些表达式
const a = 10
const b = 3
const arr = ['吃', '喝', '玩', '乐']
const flag = false
const fn = () => {
  console.log('这是一个函数')
}
const subJsx = <div>我是另一个JSX</div>

const obj = {
  a: 'Hi',
  b: '~~'
}

// 必须有一个根节点
const jsx = (
  <div>
    <div>{ a + b }</div>
    <div>{ a - b }</div>
    <div>{ a * b }</div>
    <div>{ a / b }</div>
    <div>{ a % b }</div>
    <div>{ arr }</div>
    <div>{ flag ? '真的' : '假的' }</div>
    <div>{ fn() }</div>
    <div>{ subJsx }</div>
    {/* 对象和流程控制都不能写在 {} 之间 */}
    {/* <div>{ obj }</div> */}
    {/* <div>{ for (var i = 0; i < 10; i++) {} }</div> */}
  </div>
)

ReactDOM.render(jsx, document.querySelector('#app'))

结果

2.3 条件渲染

import React from 'react'
import ReactDOM from 'react-dom'

const flag = false

const show = (flag) => {
  if (flag) {
    return (
      <div>我是真的</div>
    )
  } else {
    return (
      <div>我是假的</div>
    )
  }
}

const s = show(flag)

ReactDOM.render(s, document.querySelector('#app'))

结果

2.4循环渲染

核心思想:

  • 使用数组的 map 方法循环将每个单元的数据改造成 jsx ,并保存在一个新的数组中
  • 在 { } 中的数组是可以直接被循环渲染的
  • 注意: 要使用 key 绑定每一次循环,key 值要唯一
import React from 'react-dom'
import ReactDOM from 'react-dom'

// 目标: 将数组中的数据渲染到表格的 tbody 中
const userAry = [
  {id: 1, username: 'zs', age: 20, gender: 1},
  {id: 2, username: 'ls', age: 22, gender: 0},
  {id: 3, username: 'ww', age: 21, gender: 1}
]

const jsx = (
  <table border="1" width="500" align="center">
    <thead>
      <tr>
        <th>id</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>性别</th>
      </tr>
    </thead>

    <tbody>
    /* 使用 map 将数组中每个单元都改造成 tr-td-数据 组成的jsx */
    /* {} 中能直接遍历数组,就能显示成表格 */
      {
        userAry.map(item => {
          return (
            <tr key={item.id}>
              <td>{item.id}</td>
              <td>{item.username}</td>
              <td>{item.age}</td>
              <td>{item.gender === 1 ? '男' : '女'}</td>
            </tr>
          )
        })
      }
    </tbody>
  </table>
)

ReactDOM.render(jsx, document.querySelector('#app'))

结果

2.5 理解循环

// map的作用是对数组中的每个单元进行加工
// map循环结束之后会得到一个新的数组
// {} 能直接循环数组并渲染每个单元
const hobbies = ['吃', '喝', '玩', '乐']

const arr = hobbies.map(item => {
  return <div>{item}</div>
})

const jsx = (
  <div>{ arr }</div>
)

结果

2.6 样式处理

两种方式:

  • 行内样式 — style
  • 类名 — className
  1. style 方式: 对象形式设置样式 (不推荐)
const jsx = <div style={ {color: 'red', fontSize: '32px'} }>Hello World</div>
  1. className方式
  • className 就是标签中的 class属性,在 jsx 中必须使用 className
  • css样式写在一个独立的文件内
  • 使用 import 导入css文件
import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 将 Hello World 字符串变为红色,字体大小为32px
import './assets/css/index.css'
const jsx = <div className='title'>Hello World</div>

ReactDOM.render(jsx, document.querySelector('#app'))

结果

2.7 总结

  • JSX 是在js代码中编写html结构,是React声明式的一个体现
  • JSX 中可以使用各种表达式,表达式要写在 { } 中
  • JSX 中条件渲染是用函数完成的,在函数内计算出最终的 JSX 再在 { } 中调用该函数
  • JSX 中的循环渲染使用 map 方法
  • JSX 中使用样式有 style 和 className 两种方式
    • style中使用对象方式设置样式;
    • className中来设置类名,样式写在另一个文件中,切记使用 import 调出css文件

3. React 组件基础

  • 组件是React中最重要的技术,使用 React 就是在使用各种组件
  • 组件表示页面中的部分功能
  • 通常,一个完整的页面时由多个组件组合而成的
  • 特点: 可复用、可组合、独立

3.1 使用函数创建组件

  • 使用函数创建的组件叫做 函数组件
  • 函数名称首字母必须以大写字母开头
  • 函数组件必须有返回值,而且是 JSX 结构; 返回值可以为 null, 意思是不渲染任何内容
  • 使用函数名作为组件标签名
import React from 'react'
import ReactDOM from 'react-dom'

// 定义函数组件
function MyComp () {
  return (
    <div>这是我的第一个函数组件</div>
  )
}

// 可以直接渲染组件
// ReactDOM.render(<MyComp></MyComp>, document.querySelector('#app'))
// 如果组件中没有其他子节点,可以改为单标签形式
ReactDOM.render(<MyComp />, document.querySelector('#app'))

3.2 使用类创建组件

  • 使用 class 创建的组件叫做 类组件
  • 类名需要大写,必须继承 React.Component 父类
  • 继承父类就意味着能够调用父类中提供的属性和方法
  • 类组件必须要有 render 方法,返回 JSX
import React from 'react'
import ReactDOM from 'react-dom'

class Hello extends React.Component {
  render () {
    return (
      <div>这是我的第一个类组件</div>
    )
  }
}

ReactDOM.render(<Hello></Hello>, document.querySelector('#app'))

3.3 组件抽离

将每个组件放到单独的js文件中,组件就会更加易于开发和维护

目标: 创建一个独立的 MyCom 组件,并在 index.js 使用该组件

步骤:

  1. 创建 MyCom.js 文件 (组件文件,内部可以使用函数组件或者类组件)

  2. 在 index.js 文件中导入 MyCom.js 文件,再渲染组件

代码实现:

1)创建 MyCom.js 文件 (组件文件,内部可以使用函数组件或者类组件)

在 src 下创建 components 目录,专门存放组件

// 1. 导入 React 包
import React from 'react'

// 2. 创建一个类组件 (函数组件同理)
class MyCom extends React.Component {
  render () {
    return (
      <div>我是一个类组件--已经被抽离出来了</div>
    )
  }
}

// 定义一个函数组件
const MyCom1 = () => {
  return (
    <div>MyCom1--函数组件</div>
  )
}

// 3. 导出组件
export default {
  MyCom,
  MyCom1
}

2)在 index.js 文件中导入 MyCom.js 文件,再渲染组件

import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 创建一个独立的 MyCom 组件,并在 index.js 使用该组件
import Com from './components/Mycom'

ReactDOM.render(<Com.Mycom />, document.querySelector('#app'))

结果

3.4 事件处理

  • 语法: on+事件名称={事件处理程序}, 例如: onClick={()=>{}}

  • 注意: 事件名必须用驼峰命名法,例如: onMouseEnter、onKeyUp

目标:创建组件,内部包含一个按钮,并给按钮绑定点击事件

import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 在按钮上注册一个点击事件,弹出一个对话框
class Show extends React.Component {
  // 定义事件处理函数
  handleClick () {
    alert('我被点了一下')
  }

  render () {
    return (
      <button onClick={this.handleClick}>点我</button>
    )
  }
}

ReactDOM.render(<Show />, document.querySelector('#app'))

3.5 事件对象

  • 事件处理函数中的参数就是事件对象
  • React 中的事件对象叫做 合成事件(对象),能兼容所有浏览器
import React from 'react'
import ReactDOM from 'react-dom'

// 目标:为文本框绑定键盘弹起事件,终端输出当前按键的ascii码
class Show extends React.Component {
  // 事件处理函数中的参数就是事件对象
  handleKeyUp (e) {
    console.log(e.keyCode)
  }

  render () {
    return (
      <input type="text" onKeyUp={this.handleKeyUp} />
    )
  }
}

ReactDOM.render(<Show />, document.querySelector('#app'))

3.6 函数形式实现事件

目标: 使用函数方式定义组件,实现键盘弹起事件输出ascii码

import React from 'react'
import ReactDOM from 'react-dom'

const handleKeyUp = (e) => {
  console.log(e.keyCode)
}

const Show = () => {
  return (
    <input type="text" onKeyUp={handleKeyUp} />
  )
}

ReactDOM.render(<Show />, document.querySelector('#app'))

4. 有状态和无状态组件

  • 函数组件叫做无状态组件;类组件叫做有状态组件
  • 状态 (state),组件中使用的数据都保存在 state 中,并且是组件的私有数据
  • 函数组件只负责数据展示(静)
  • 类组件有状态,负责动态展示 UI 界面 (动)

4.1 state的基本使用

state用来为组件绑定私有数据,有两种绑定形式

第一种: 在构造函数中定义 state

第二种: 在类中直接定义state (推荐)

案例: 在类组件中定义私有数据,并在页面上渲染出来

import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 使用 state 定义数据,并在页面上展示出来
class Hero extends React.Component {
  // 定义state (数据)
  state = {
    name: '安琪拉',
    level: 1,
    hp: 680,
    mp: 320
  }

  render () {
    // 使用 {} 调用数据
    return (
      <div>
        <ul>
          <li>英雄: {this.state.name}</li>
          <li>等级: {this.state.level}</li>
          <li>血量: {this.state.hp}</li>
          <li>蓝量: {this.state.mp}</li>
        </ul>
        <button>1</button>
      </div>
    )
  }
}

ReactDOM.render(<Hero />, document.querySelector('#app'))

4.2 修改数据

setState() 方法用来修改数据

state = {
    name: 'zs',
    age: 20
}

this.setState({
    name: 'ls',
    age: 25
})

目标:上例中button按钮上注册点击事件,每升一级,hp增加100,mp增加120

核心: 修改数据需要使用到 setState 方法,方法内是一个对象参数,要修改哪个数据写哪个数据即可

this.setState({
  level: this.state.level + 1,
  hp: this.state.hp + 100,
  mp: this.state.mp + 120
})

注意:千万别习惯性写成 this.state.level = this.state.level + 1 或者 this.state.level += 1

代码实现:

import React from 'react'
import ReactDOM from 'react-dom'

class Hero extends React.Component {
  // 定义state (数据)
  state = {
    name: '安琪拉',
    level: 1,
    hp: 680,
    mp: 320
  }

  render () {
    // 使用 {} 调用数据
    return (
      <div>
        <ul>
          <li>英雄: {this.state.name}</li>
          <li>等级: {this.state.level}</li>
          <li>血量: {this.state.hp}</li>
          <li>蓝量: {this.state.mp}</li>
        </ul>
        <button onClick={() => {
          this.setState({
            level: this.state.level + 1,
            hp: this.state.hp + 100,
            mp: this.state.mp + 120
          })
        }}>1</button>
      </div>
    )
  }
}

ReactDOM.render(<Hero />, document.querySelector('#app'))

4.3 this 指向

  • 如果将 onClick 指定的事件函数独立出来定义成一个函数则会报错
  • 原因: this 的指向不同
    • 事件函数直接定义在类当中,this指向 undefined
    • 事件函数写在 onClick 中,this指向 Hero 组件
  • 解决:
    • 使用箭头函数代替传统函数
    • 使用bind方法修改this指向 this.upLevel = this.upLevel.bind(this)
    • call、apply、bind

箭头函数方式:

import React from 'react'
import ReactDOM from 'react-dom'

class Hero extends React.Component {
  // 定义state (数据)
  state = {
    name: '菊花信',
    level: 1,
    hp: 680,
    mp: 320
  }

  // 使用箭头函数代替传统函数方式,调整this的指向
  upLevel = () => {
    this.setState({
      level: this.state.level + 1,
      hp: this.state.hp + 100,
      mp: this.state.mp + 120
    })
  }

  render () {
    // 使用 {} 调用数据
    return (
      <div>
        <ul>
          <li>英雄: {this.state.name}</li>
          <li>等级: {this.state.level}</li>
          <li>血量: {this.state.hp}</li>
          <li>蓝量: {this.state.mp}</li>
        </ul>
        <button onClick={this.upLevel}>1</button>
      </div>
    )
  }
}

ReactDOM.render(<Hero />, document.querySelector('#app'))

bind方式:

import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 使用点击事件,每升一级,血量增加100,蓝量增加120
class Hero extends React.Component {
  constructor () {
    super()

    // 定义state (数据)
    this.state = {
      name: '安琪拉',
      level: 1,
      hp: 680,
      mp: 320
    }

   // 使用传统函数方式,则需要使用 bind 方法修改 this 指向
   // 修改upLevel的this指向
   // 注意不能马上执行该函数,所以只能用 bind
   // 此处的this指的是App类的实例对象
    this.upLevel = this.upLevel.bind(this)
  }

  // 使用传统方式定义事件函数时,函数内部的this是undefined
  upLevel () {
    this.setState({
      level: this.state.level + 1,
      hp: this.state.hp + 100,
      mp: this.state.mp + 120
    })
  }

  render () {
    // 使用 {} 调用数据
    return (
      <div>
        <ul>
          <li>英雄: {this.state.name}</li>
          <li>等级: {this.state.level}</li>
          <li>血量: {this.state.hp}</li>
          <li>蓝量: {this.state.mp}</li>
        </ul>
        <button onClick={this.upLevel}>1</button>
      </div>
    )
  }
}

ReactDOM.render(<Hero />, document.querySelector('#app'))

5. 受控组件

5.1 受控组件介绍

  • 受控组件通常指的是表单,因为表单是可输入的,必须有对应的状态与之绑定
  • React 将 state与表单的 value值绑定到一起
  • 给表单元素绑定change事件,将表单元素的值设置为state的值,接收表单值变化

核心代码:

// 1. state 中设置数据
state = {
    username: 'admin'
}

// 2. 表单域中将 state中的数据与value绑定
// 3. 文本框每次内容发生变化都会触发 change 事件,可以在事件函数中将文本框中的最新数据更新到 state 中
<input 
    type="text" 
    value={this.state.username}    //value与username绑定,所以文本框中默认写入 admin
    onChange={this.handleText}
/>

// 事件函数中调用 setState 将数据进行保存
// 参数: e 是事件对象
//  e.target 中保存了标签的 DOM 对象
//  e.target.value 保存了input中的value
//  e.target.name 保存了input的name值
handleText = (e) => {
    this.setState({
        username: e.target.value
    })
}

案例:获取用户名文本框中的内容

import React from 'react'
import ReactDOM from 'react-dom'

// 目标: 点击登录按钮,将文本框中的值输出到终端

class App extends React.Component {
  state = {
    account: ''
  }

  checkLogin = () => {
    console.log(this.state)
  }

  // 文本框内容变化时数据的处理函数
  handleAccount = e => {
    console.log(e)
    this.setState({account: e.target.value})
  }

  render () {
    return (
      <div>
        账号: <input type="text" value={this.state.account} onChange={this.handleAccount} /><br />
        <button onClick={this.checkLogin}>登录</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.querySelector('#app'))

5.2 不同域数据的获取方式

  • 每个域都要将 value 和 state 中对应的属性绑定
  • 每个域都要绑定 onChange 事件
import React from 'react'
import ReactDOM from 'react-dom'


class App extends React.Component {
  state= {
    username: '张三',
    city: 'xa',
    sign:'是个好玩的地方'
  }
  // handleText事件能够监听文本框中发生的变化
 handleText =async (e)=>{
    await this.setState({
      username:e.target.value
    })
    console.log(this.state.username);
  }
  handleSelect =async e =>{
    await this.setState({
      city:e.target.value
    })
    console.log(this.state.city);
  }
    handleArea = async e =>{
      await this.setState({
        sign:e.target.value
      })
      console.log(this.state.sign);
    }
    
  render () {
    return (
      <div>
        姓名: <input type="text" value={this.state.username} onChange={this.handleText}/><br />
        城市:<select value={this.state.city} onChange={this.handleSelect}>
              <option value='bj'>北京</option>
              <option value='sh'>上海</option>
              <option value='xa'>西安</option>
            </select><br/>
        简介:<textarea value={this.state.sign} onChange={this.handleArea}></textarea>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.querySelector('#app'))

5.3 合并处理

核心: e.target

  • e.target.value : 保存了标签中的value值
  • e.target.name:保存了标签中的name值

解决方案: 每个域中name属性绑定 state 中对应的属性, onChange指定一个函数统一处理

import React from 'react'
import ReactDOM from 'react-dom'


class App extends React.Component {
  state= {
    username: '张三',
    city: 'xa',
    sign:'是个好玩的地方'
  }
  // e.target是对应域的DOM对象
  // DOM value 保存了数据 name 保存了域的名称
 handleText =async (e)=>{
   const { name,value } = e.target
  //  console.log(name,value);
    await this.setState({
      // username:e.target.value
      [name]: value
    })
    console.log(this.state);
  }

    
  render () {
    return (
      <div>
        姓名: <input name='username' type="text" value={this.state.username} onChange={this.handleText}/><br />
        城市:<select name='city' value={this.state.city} onChange={this.handleText}>
              <option value='bj'>北京</option>
              <option value='sh'>上海</option>
              <option value='xa'>西安</option>
            </select><br/>
        简介:<textarea name='sign' value={this.state.sign} onChange={this.handleText}></textarea>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.querySelector('#app'))

6. 非受控组件(了解)

使用步骤:

  • 在构造函数中调用 React.createRef() 方法创建一个 ref 对象
  • 将 ref 对象绑定到对应的域
  • 通过ref 对象获取域的值
  • 该方式是一种直接操作DOM的方式,不推荐
import React from 'react'
import ReactDOM from 'react-dom'

class FormData extends React.Component {
  constructor () {
    super()

    //1. 在构造方法中创建 ref 对象
    this.txtRef = React.createRef()
  }

  getData = () => {
    console.log(this.txtRef.current.value)
  }

  render () {
    return (
      <div>
        {/* 在域中使用 ref属性 绑定 ref对象 */}
        <input type="text" ref={this.txtRef} /><br />
        <button onClick={this.getData}>获取数据</button>
      </div>
    )
  }
}

ReactDOM.render(<FormData />, document.querySelector('#app'))

7. 综合案例

目标: 完成表单添加英雄,表格渲染英雄功能,表格删除英雄功能,表格点击修改数据渲染到表单确认修改表单数据更新到表格功能。

import React from 'react'
import ReactDOM from 'react-dom'
import './assets/css/cmt.css'


class Comment extends React.Component {
  // 定义表格中使用的数组
  state = {
    heros: [
      { id: 1, heroname: '艾希', nickname: '寒冰射手', age: 180, gender: '女'},
      { id: 2, heroname: '盖伦', nickname: '德玛西亚之力', age: 26, gender: '男'},
      { id: 3, heroname: '瑞兹', nickname: '符文法师', age: 1200, gender: '男'},
    ],
    // 定义表单中使用数据
    id: '',
    heroname: '',
    nickname: '',
    age: '',
    gender: '',
  }

  // 确认修改表单数据
  editData=()=>{
    const {heros} = this.state
    this.state.heros.map((item)=>{
      if(item.id === this.state.id){
        item.heroname = this.state.heroname
        item.nickname = this.state.nickname
        item.age = this.state.age
        item.gender = this.state.gender
      }
    })
    this.setState({
      heros,
      // 清空表单
      id: '',
      heroname: '',
      nickname: '',
      age: '',
      gender: ''
    })
  }

  // 删除表格中的数据
  deleteData = (e) => {
    console.log(e.target.value);
      const {heros} = this.state
      const isIndex = (item) => item.id === e.target.value;
      heros.splice(heros.findIndex(isIndex),1)
      // console.log(heros.splice(heros.findIndex(isIndex),1)); 
        this.setState({
          heros:heros
        })
  }
  // 修改表格数据渲染到表单中
  // handleData = () => {
  //   let handleHero = this.state.heros.map(item => {
  //     this.setState({
  //       id: item.id,
  //       heroname: item.heroname,
  //       nickname: item.nickname,
  //       age: item.age,
  //       gender: item.gender
  //     })
  //     return handleHero
  //   })
  // }
  



  // 将渲染表格代码单独抽取出来
  renderList = () => {
    // 判断英雄数组中是否有数据
    if (this.state.heros.length === 0) {
      // 没有则返回 暂无英雄数据 信息
      return (
        <tr>
          <td colSpan="5" align="center">暂无英雄数据</td>
        </tr>
      )
    } else {
      // 有则使用map方法将数组单元数据全部重组, 再返回
      let tmpAry = this.state.heros.map(item => {
      // 修改表格数据显示到表单中
      let handleData = ()=>{
        this.setState({
          id: item.id,
          heroname: item.heroname,
          nickname: item.nickname,
          age: item.age,
          gender: item.gender
        })
        return handleData
      }
      // 删除表格中的英雄数据
      // let deleteData = ()=> {
      //   const {heros} = this.state
      //   this.state.heros.map((data) =>{
      //     if (data.id === item.id){
      //       // let arr = heros.splice(data ,1)
      //       const isIndex = (item) => item.id === data.id;
      //       heros.splice(heros.findIndex(isIndex),1)
      //       // console.log(heros.splice(heros.findIndex(isIndex),1)); 
      //     }
      //     this.setState({

      //     })
      //   })
      // }
        return(
          <tr key={item.id}>
            <td>{item.id}</td>
            <td>{item.heroname}</td>
            <td>{item.nickname}</td>
            <td>{item.age}</td>
            <td>{item.gender}</td>
            <td>
            <button onClick={handleData}>修改</button>
            <button  value={item.id} onClick={this.deleteData}>删除</button>
            </td>
          </tr>
        )
      })
      return tmpAry
    }
  }

  

  addHero = () => {
    // 1. 解构所有数据
    const {heros, heroname, nickname, age, gender} = this.state

    if (heroname.trim() === '' || nickname.trim() === '' || age.trim === '' || gender.trim() === '') {
      alert('请完整填写表单')
      return
    }

    // 2. 构建一个新的英雄对象
    const obj = {
      id: heros.length + 1,
      heroname,
      nickname,
      age,
      gender
    }
    // 3. 将新对象追加到数组最后
    heros.push(obj)
    // 4. 更新整个数组则会直接更新页面, 重置表单
    this.setState({
      heros,
      heroname: '',
      nickname: '',
      age: '',
      gender: ''
    })
  }

  handleForm = e => {
    const {name, value} = e.target
    this.setState({
      [name]: value
    })
  }

  render () {
    return (
      <div className="container">
        <div className="form-box">
          <h3>添加新英雄</h3>
          姓名: <input type="text" name="heroname" value={this.state.heroname} onChange={this.handleForm} /><br />
          昵称: <input type="text" name="nickname" value={this.state.nickname} onChange={this.handleForm} /><br />
          年龄: <input type="text" name="age" value={this.state.age} onChange={this.handleForm} /><br />
          性别: <input type="text" name="gender" value={this.state.gender} onChange={this.handleForm} /><br />
          <button onClick={this.addHero}>添加</button>
          <button onClick={this.editData}>确定修改</button>
        </div>

        <div className="table-box">
          <table border="1" align="center" width="400">
            <caption><h3>英雄列表</h3></caption>
            <thead>
              <tr>
                <th>id</th>
                <th>姓名</th>
                <th>昵称</th>
                <th>年龄</th>
                <th>性别</th>
                <th>操作</th>
              </tr>
            </thead>

            <tbody>
              {this.renderList()}
            </tbody>
          </table>
        </div>
      </div>
    )
  }
}

ReactDOM.render(<Comment />, document.querySelector('#app'))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值