React 初级三部曲 | 8月更文挑战

438 阅读9分钟

第一节: React简介

1, 什么是React

React 是一个用于构建用户界面的JavaScript库,

用户界面: HTML页面

React 主要用来写HTML页面,或构建Web应用

如果从MVC的角度来看,React不仅仅是视图层,也就是只负责视图的渲染,而并非提供了完整的M和C的功能。

React起源于Facebook的内部项目,与2013年5月开源

2, React的特点

1,声明式

const jsx = <div className = "app">
<h1>HellO React</h1>
</div>

2,基于组件

组件是react中最重要的内容

3,学习一次,随处使用

  • 使用react可以开发web应用
  • 使用react可以开发移动端原生应用(react-native)
  • 使用react可以开发VR应用(react 360)

3, React的安装

安装命令npm install react react-dom

  • react 包是核心, 提供创建元素,组件等功能
  • react-dom 包提供DOM相关功能
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root"></div>
  <script src="./node_modules/react/umd/react.development.js"></script>
  <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
  <script>
    // 创建react 元素
    const title = React.createElement('h1', null, 'Hello World')
    // 渲染react 元素,并寻找挂载点
    ReactDOM.render(title, document.getElementById('root'))
  </script>
</body>
</html> 
  • React.createElement()说明
返回值: react元素
第一个参数: 要创建的react的元素名称
第二个参数: 该react元素的属性
第三个参数及其之后的参数: 该react元素的子节点
const title = React.createElement('h1', { title: '标题' }, 'Hello World') 
  • ReactDOM.render()说明
第一个参数: 要渲染的元素名称
第二个参数: DOM对象,用于指定渲染到页面中的位置
 ReactDOM.render(title, document.getElementById('root'))

第二节:React 脚手架

1, React脚手架意义

1, 脚手架是开发,现代web应用的必备
2, 充分的利用webpack, babel, eslint等工具辅助项目开发
3, 零配置,而不是工具配置

2, React项目初始化

npx create-react-app my-app

cd my-app

yarn start

3, npx 命令介绍

npm v5.2.0引入的一条命令,目的是提升包内提供的命令行工具的使用体验。

原来:需要先安装脚手架包,现在无需安装脚手架包,可以直接使用这个包提供的命令。

推荐使用

npx create-react-app myProject

还有另外两种方式:

1, npm init react-app myProject

2, yarn create react-app myProject

4, JSX的基本使用

1, createElement()的问题

繁琐不简洁, 不直观,无法一眼看出所描述的结构,不优雅,用户体验不爽
React.createElement(
 'div',
 {className: 'shopping-list'},
 React.createElement('h1', null, 'shopping-list'),
 React.createElement(
  'ul',
  null,
  React.createElemenet('li', null, 'Instagegram'),
  React.createElemenet('li', null, 'WhatApp')
 )
)

2, JSX 语法,等同于HTML语法

同一的页面结构,用JSX语法实现

<div className="shopping-list">
  <h1>Shopping-list</h1>
  <ul>
    <li>Instagegram</li>
    <li>WhatSapp></li>
  </ul>
</div>

JSX就是JavaScript XML的简写,表示在JavaScript代码中写XML格式的代码,与HTML结构相同,降低了学习成本,提升了开发效率,JSX是React的核心内容

3,JSX的基本使用步骤

(1)使用JSX语法,创建react元素

const title = <h1>Hello JSX</h1>

(2) 使用ReactDOM.render()渲染react元素到页面中

ReactDOM.render(title, root)

4,为什么脚手架中可以使用JSX语法?

1, JSX 不是标准的ECMAScript语法,需要使用babel编译处理后,才能在浏览器中使用,
2, create-react-app脚手架中已经默认有该配置,无需手动配置
3, 编译JSX的语法包: @babel/preset-react

5, JSX 语法

注意点

1, React元素的属性名使用:驼峰命名法

2,特殊属性名:

class —> className

for—> htmlFor

tabindex—> tabIndex

3, 没有子节点的React 元素可以用 />结束

4,推荐: 使用小括号包裹JSX,从而避免JS中的自动插入分号陷阱

const div = (
  <div>使用小括号包裹</div>
)

6, JSX 中使用JavaScript

条件渲染

1, 语法: { javaScript }

注意: 是单大括号, 不是双大括号

三元表达式

const isLoading = true
const loadData = () => {
  return isLoading ? (<div>loading....</div>) : (<div>加载成功之后的数据</div>)
}

逻辑与运算符

const loadData = () => {
  return isLoading && (<div>loading...</div>)
}

列表渲染

  • 如果要渲染一组数据,应该使用数组的map()方法

  • 注意: 渲染列表时,应该添加key属性,key属性的值要保证唯一

  • 原则: map()遍历谁,就给谁添加key属性

const lista = (
  <ul>
    {
      songs.map( item => {
       return <li key={item.id}>{item.name}</li>
      })
    }
  </ul>
)

JSX样式处理

(1) 行内样式 —style

 <ul style={{color: 'red', background: 'skyblue'}}>
  JSX的行内样式
 </ul>

(2) 类名— className(推荐)

7, 总结

1, JSX 是React的核心内容

2, JSX表示在JS代码中写HTML结构,是React声明式的体现

3, 使用JSX配合嵌入的JS表达式,条件渲染,列表渲染,可以描述任意UI结构

4, 推荐使用className的方式给JSX添加样式

5, React 完全利用JS语言自身的能力来编写UI,而不是造轮子增强HTML功能

第三节:React 组件渲染

1, React 组件介绍

组件是react的一等公民,使用React就是在使用组件,组件表示的是页面中的部分功能,多个组件组合起来实现完整的页面功能

组件特点:可复用,独立,可组合

2, 组件的两种创建方式

  • 函数组件

    (1) 使用JS的函数创建的组件,或箭头函数

    (2) 函数名称必须以大写字母开头

    (3) 函数组件必须有返回值,表示该组件的结构

    (4) 如果返回值为null, 表示不渲染任何东西

function Hello() {
   return (
     <div>这是函数组件</div>
   )
}
const Say = () => {
  return (
    <div>箭头函数式组件</div>
  )
}

函数式组件使用方式:

(1) 用函数名作为组件标签名

(2) 组件标签可以是单标签也可以是双标签

ReactDOM.render(<Hello />, root)
  • 类组件 (1) React事件绑定语法与DOM事件语法相似

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

(3) 注意:React 事件采用驼峰命名法,比如:onMouseEnter, onFocus

(4) 在函数组件中绑定事件,是没有this

   class Hello2 extends React.Component {
     render() {
         return (
           <div>我是类组件</div>
           )
     }
   }
   ReactDOM.render(
     <Hello2 />,
     document.getElementById('root')
   );
  • 事件处理对象

(1)可以通过事件处理程序的参数获取到事件对象

class Hello2 extends React.Component {
  handleClick(e) {
    // 阻止a标签的默认行为
    e.preventDefault();
    console.log('a标签的点击事件触发了')
  }
  render() {
      return (
        <div>
          <a href="http://www.baidu.com" onClick={this.handleClick}>我是类组件</a>
        </div>
     )
  }
}

4, 有状态组件和无状态组件

  • 函数组件又叫做无状态组件, 类组件又叫做有状态组件
  • 状态(state)即数据
  • 函数组件没有自己的状态,只负责数据展示(即静态页面)
  • 类组件有自己的状态,负责更新UI,让页面动起来

5, 组件中的state 和 setState

(1) 状态即数据,是组件内部的私有数据,只能在组件内部使用

(2) state的值是对象,表示一个组件中更可以有多个数据

(3) 通过this.state来获取状态

import React from 'react'
class Hello2 extends React.Component {
   state = {
          count: 304
    }
   render() {
      return (
        <div>
            <h1>{this.state.count}</h1>
        </div>
     )
  }
}

(4)状态是可变的,可以通过setState() 修改状态,

(5)语法 this.setState( {要修改的数据} )

注意: 不要直接修改state中的值,这是错误的

this.setState({
  count: this.state.count + 1
})

(6)setState的作用:

1,修改state,

2, 更新UI

思想:数据驱动视图

6, JSX中抽离事件处理程序

  • JSX中参杂了过多的JS逻辑代码,会显示非常混乱

  • 推荐:将逻辑抽离到单独的方法中,保证JSX结构清晰

    注意: 事件处理程序中的this的值为: undefined

  • 我们希望: this指向组件实例,记住: render方法中的this即为组件实例

7, 解决事件绑定this指向

(1) 箭头函数 箭头函数自身不绑定this的特点,谁调用它,它就指向当前实例

onIncremnet() {
      console.log('当前this的值', this)
      this.setState({
         count: this.state.count + 1
      })
   }
render() {
  // 箭头函数中的this指向外部环境,此处为:render()方法,render方法中      // 的this就是组件实例
   return (
     <button onClick={()=> this.onIncrement()}></button>
   )
}

(2) Function.prototype.bind() 利用ES5中的bind方法,将事件处理程序中的this与组件实例绑定到一起

class Hello2 extends React.Component {
   constructor() {
      super()
      this.state = {
         count: 304
      }
      this.onIncremnet = this.onIncremnet.bind(this)
   }
   onIncremnet() {
      console.log('当前this的值', this)
      this.setState({
         count: this.state.count + 1
      })
   }
   render() {
      return (
        <div>
            <h1>{this.state.count}</h1>
            <button onClick={ this.onIncremnet}>+1</button>
        </div>
     )
  }
}

(3)在class实例的方法中,利用箭头函数 因为箭头函数中不绑定this, 所以箭头函数中的this指向的就是当前组件实例

class Hello2 extends React.Component {
   constructor() {
      super()
      this.state = {
         count: 304
      }
   }
   onIncremnet =() => {
      console.log('当前this的值', this)
      this.setState({
         count: this.state.count + 1
      })
   }
   render() {
      return (
            <button onClick={ this.onIncremnet }>+1</button>
     )
  }
}

8, React中的表单处理

一,受控组件

  • 1,HTML 中的表单元素是可输入的,也就是有自己的可变状态
  • 2,React的可变状态保存在state中,并且只能通过setState()方法来修改
  • 上面1,2两点相互冲突,都想通过自己的方式控制表单元素值,最好的办法就是:将React中的state与表单元素值value绑定到一起,有state的值来控制表单元素的值, 而改变state的值,只能通过setState方法
<input type="text" value={this.state.txt} 
  onChange = { e => this.setState({ txt: e.target.value})}
  />

DEMO 常用的表单获取值

import React from 'react'class FormText extends React.Component {
   constructor() {
      super()
      this.state = {
         txt: '',
         content: '',
         city: 'bj',
         isChecked: false
      }
   }
   handleChange =(e) => {
      this.setState({
         txt: e.target.value
      })
   }
   handleContent = (e) => {
      this.setState({
         content: e.target.value
      })
   }
   handleCity = (e) => {
      this.setState({
         city: e.target.value
      })
   }
   hanldeChecked = (e) => {
      this.setState({
         isChecked: e.target.checked
      })
   }
   render() {
      return (
        <div>
            <input type="text" value={this.state.txt} onChange={this.handleChange}></input>
            <br />
            <textarea value={this.state.content} onChange={this.handleContent}></textarea>
            <br />
            <select value={this.state.city} onChange={this.handleCity}>
                <option value="sh">上海</option>
                <option value="bj">北京</option>
                <option value="sz">深圳</option>
                <option value="gz">广州</option>
            </select>
            <br />
            <input type="checkbox" checked= {this.state.isChecked} onChange=
            {this.hanldeChecked}></input>
        </div>
     )
  }
}
export default FormText

总结 1, 文本框,富文本框,下拉框,操作的都是value属性: e.target.value

2, 复选框操作的是 checked属性: e.target.checked

3,受控表单的优化

  • (1)给表单元素添加name属性,名称与state相同
  • (2)根据表单元素类型获取对应值
  • (3)在change事件处理程序中通过[name]来修改对应的state
import React from 'react'
class FormText extends React.Component {
   constructor() {
      super()
      this.state = {
         txt: '',
         content: '',
         city: 'bj',
         isChecked: false
      }
   }
   handleForm =(e) => {
      debugger
      // 获取当前DOM对象
      const target = e.target
      // 根据类型获取值
      const value = target.type === 'checkbox' ? target.checked : target.value
      // 获取name
      const name = target.name
      this.setState({
         [name]: value
      })
   }
   render() {
      return (
        <div>
            <input  name="txt" type="text" value={this.state.txt} onChange=
            {this.handleForm}></input>
            <br />
            <textarea name="content" value={this.state.content} onChange=
            {this.handleForm}></textarea>
            <br />
            <select name="city" value={this.state.city} onChange={this.handleForm}>
                <option value="sh">上海</option>
                <option value="bj">北京</option>
                <option value="sz">深圳</option>
                <option value="gz">广州</option>
            </select>
            <br />
            <input name="isChecked" type="checkbox" checked= {this.state.isChecked} 
            onChange={this.handleForm}></input>
        </div>
     )
  }
}
export default FormText

二, 非受控组件 1, 非受控组件使用步骤:调用 React.createRef() 方法创建一个ref对象

construtor() {
  super()
  this.txtRef = React.createRef()
}
<input type="text" ref={this.txtRef} />
console.log(this.txtRef.current.value)

注意: 不要忘记current

3, 通过ref对象获取到文本框的值

2, 将创建好的ref对象添加到文本框中,相互绑定

9, 总结

React 组件基础

1, 组件的两种创建方式: 函数组件和类组件

2,函数组件又称无状态组件,负责静态结构展示

3,类组件又称有状态组件,负责更新UI,让页面动起来

4,绑定事件注意this的指向问题

5,推荐使用受控组件来处理表单

6,完全利用JS语言的能力创建组件,这就是React思想

发布评论的DEMO

import React from 'react'class Form extends React.Component {
    // 初始化状态
    state = {
        comments: [
            { id: 1, name: 'jack', content: '沙发'},
            { id: 2, name: 'rose', content: '板凳'},
            { id: 3, name: 'tom',  content: '楼主好人'}
        ],
        // 评论人
        userName: '',
​
        // 评论内容
        userContent: ''
    }
    // 处理表单元素值
    handleForm = (e) => {
        const { name, value } = e.target
        this.setState({
            [name]: value
        })
    }
    // 发布评论
    handleClick = () => {
        const { comments, userName, userContent } = this.state
​
        if (userName.trim() === '' || userContent.trim() === '') {
            return
        }
        const newComments = [{
            id: Math.random(),
            name: userName,
            content: userContent
        },...comments]
        // 赋值,并清空文本框的值
        this.setState({
            comments: newComments,
            userName: '',
            userContent: ''
        })
    }
    // 渲染评论列表
    renderList() {
        const { comments } = this.state
        return comments.length === 0 
        ? 
        ( <div className="no-comment">暂无评论,快去评论吧</div>)
        :
        ( <ul>
          { comments.map(item => {
              return (
                  <li key={item.id}>
                      <h3>评论人:{item.name}</h3>
                      <span>评论内容:{item.content}</span>
                  </li>
              )
          })}
          </ul>
        )
    }
    render() {
        const { userName, userContent } = this.state
        return (
          <div className="form">
            <div>
              <input className="user" type="text" placeholder="请输入评论人" value=
              {userName} name="userName" onChange={this.handleForm}></input>
              <br />
              <textarea
                className="content"
                cols="30"
                rows="10"
                name="userContent"
                value={userContent}
                onChange={this.handleForm}
                placeholder="请输入评论内容"
              />
              <br />
              <button onClick={this.handleClick}>发布评论</button>
            </div>
            { /* 通过条件渲染决定渲染内容 */}
            {
              this.renderList()
            }
            
          </div>
        )
    }
}
export default Form;