React框架基础

目录

一、概述

二、特点

三、react与与传统mvc的关系

四、浏览器扩展与vscode开发扩展安装

 五、命令行构建项目

5.1  脚手架

5.2  创建react项目

 六、jsx

6.1  概念

6.2  语法

6.2.1  插值语法

6.2.2  动态绑定属性

6.2.3  数组列表渲染

6.2.4  渲染对象列表

七、React事件处理

7.1  事件绑定

 7.2 传值

 7.3  事件对象

7.4  this.指向问题 

八、state状态

8.1 基本使用

8.2  修改状态

8.3  props和state的区别

8.4  关于state的深度思考 

九、 Props进阶

9.1  children属性

9.2  类型限制(Props-type)

 9.3  默认值

十、表单处理

10.1  受控组件

10.2 非受控组件


一、概述

​ React 起源于 Facebook(脸书) 的内部项目,它是一个用于构建用户界面的 javascript 库,Facebook用它来架设公司的Instagram网站,并于2013年5月开源。

​ React 拥有较高的性能,代码逻辑非常简单,越来越多的人已开始关注和使用它。认为它可能是将来 Web 开发的主流工具之一。

二、特点

Ø 声明式

你只需要描述UI看起来是什么样式,就跟写HTML一样,React负责渲染UI

Ø 基于组件

组件时React最重要的内容,组件表示页面中的部分内容

Ø 学习一次,随处使用

使用React可以开发Web应用(ReactJs),使用React可以开发移动端(react-native),可以开发VR应用(react 360)

三、react与与传统mvc的关系

React用于构建用户界面的 JavaScript 库,它不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。可以简单地理解为,React 将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

四、浏览器扩展与vscode开发扩展安装

React框架基础_第1张图片

React框架基础_第2张图片

 五、命令行构建项目

5.1  脚手架

React团队主要推荐使用create-react-app来创建React新的单页应用项目的最佳方式。

React脚手架(create-react-app)意义

Ø 脚手架是官方提供,零配置,无需手动配置繁琐的工具即可使用

Ø 充分利用 Webpack,Babel,ESLint等工具辅助项目开发

Ø 关注业务,而不是工具配置

create-react-app会配置你的开发环境,以便使你能够使用最新的 JavaScript特性,提供良好的开发体验,并为生产环境优化你的应用程序。你需要在你的机器上安装 Node >= 8.10 和 npm >= 5.6。

5.2  创建react项目

# 全局安装
npm install -g create-react-app
# 构建一个my-app的项目
create-react-app my-app  或 npx create-react-app my-appl

 安装成功

React框架基础_第3张图片

 六、jsx

6.1  概念

由于通过React.createElement()方法创建的React元素有一些问题,代码比较繁琐,结构不直观,无法一眼看出描述的结构,不优雅,开发时写代码很不友好。

​ React使用 JSX 来替代常规的JavaScript,JSX 可以理解为的JavaScript语法扩展,它里面的标签申明要符合XML规范要求。React不一定非要使用JSX,但它有以下优点:

Ø JSX 执行更快,因为它在编译为JavaScript代码后进行了优化

Ø 它是类型安全的,在编译过程中就能发现错误

Ø 声明式语法更加直观,与HTML结构相同,降低了学习成本,提升开发效率速

Ø jsx语法中一定要有一个顶级元素包裹,否则编译报错,程序不能运行

6.2  语法

6.2.1  插值语法

在jsx语法中,要把JS代码写到{ }中,所有标签必须要闭合。

let num = 100
let bool = false;

// JSX 语法  
//变量,部分表达式,三元,函数
var myh1 = (
  
{/* 我是注释 */} {num}
{/* 三目运算 */} {true ? "条件为真" : "条件为假"}
)

6.2.2  动态绑定属性



6.2.3  数组列表渲染

6.2.4  渲染对象列表

  let obj = {
        name:'大壮',
        age:22,
        address:'北京'
    }
    const mydiv = 
    { Object.keys(obj).map((val,index)=>{ return
  • { val } --- { obj[val] }
  • }) }
ReactDOM.render(mydiv, document.getElementById('app') )

七、React事件处理

7.1  事件绑定

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

Ø React 事件的命名采用小驼峰式,而不是纯小写。

onClick onChange

Ø 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

onClick={this.fn} // 注函数或方法不能用小括号

Ø 类组件与函数组件绑定事件是差不多的,只是在类组件中绑定事件函数的时候需要用到this,代表指向当前的类的引用,在函数中不需要调用 

类组件:

React框架基础_第4张图片

函数组件:

React框架基础_第5张图片

 7.2 传值

正确的写法用匿名函数回调函数进行传值

React框架基础_第6张图片

 7.3  事件对象

React中可以通过事件处理函数的参数获取到事件对象,它的事件对象叫做:合成事件,即兼容所有浏览器,无需担心跨浏览器兼容问题,此事件对象还拥有和浏览器原生事件相同的接口,包括 stopPropagation()和 preventDefault(),如果你想获取到原生事件对象,可以通过 e.nativeEvent 属性来进行获取。

作用:获取dom元素

react中的实现没有提供像vue中的事件修饰符,像冒泡和默认行为,需要开发者自行解决。

函数组件:

import React,{ Component } from 'react'
function Cmp(props) {
    const fn = (e) =>{
        //获取当前dom
        console.log(e.target);
        //元素中的值
        console.log(e.target.innerText);
        //获取属性
        console.log(e.target.getAttribute('name'));
        //取消默认行为
        e.preventDefault()
    }
    return (
      
点击事件
) } export default Cmp

 合成事件对象

  • 所有事件都挂在到document上

  • event不是原生的,是syntheticEvent合成事件对象

  • 和vue事件不同和dom事件也不同

React框架基础_第7张图片

react为何要合成事件机制?

  1. 更好的兼容性和跨平台

  2. 挂在到document,减少内存消耗,避免频繁解绑

  3. 方便事件统一管理(如事务机制)

7.4  this.指向问题 

在JSX事件函数方法中的 this,默认不会绑定 this指向。如果你忘记绑定,当你调用这个函数的时候 this 的值为 undefined。所以使用时一定要绑定好this的指向。

Ø 构造方法中绑定

import React,{ Component } from 'react'
export default class extends React.Component {
    constructor(props){
        super(props)
        // 在构造方法中指定this指向  
        this.clickHandle = this.clickHandle.bind(this)
    }
    clickHandle(){
        console.log(this);
        console.log('dianji');
    }
    render(){
        return (
            
) } }

 Ø 申明式使用bind绑定+传参

Ø 箭头函数绑定+传参 【推荐】

Ø 定义事件方法使用箭头函数来绑定

// 通过箭头函数定义事件方法,也能解决this指向问题
  clickHandle = (val) => {
        console.log(this);
        console.log('dianji');
        console.log(val);
    }
    render(){
        return (
            
) }

八、state状态

8.1 基本使用

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

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

Ø 通过this.state来获取状态,react中没有做数据代理

Ø state数据值可以修改 this.setState

Ø state可以定义在类的构造方法中也可以写在类的成员属性

export default class extends React.Component {
    constructor(props){
        super(props)
        // 第一种初始化方式
        this.state = {
            count : 0
        }
}
/*
    // 第二种初始化方式
    state = {
        count:1
	}
*/
    render(){
        return (
            
计数器 :{this.state.count}
) } }

8.2  修改状态

state中的值不能直接通过修改state中的值来进行修改数据操作,react提供一个this.setState方法来完成state数据的修改操作

setState() 作用:
	1.修改 state 
	2.更新UI
setState更新数据源是异步操作,不是同步,异步效率更高(js是单线程)

语法1
this.setState({
    key:value
})

语法2  
   this.setState(state=>{
       return{
     	  num:state.num + 1
       }
   })

8.3  props和state的区别

Ø props 中存储的数据,都是外界传递到组件中的

Ø props 中的数据,都是只读的

Ø state 中的数据,都是可读可写的

Ø props 在函数声明或类申明的组件中都有

Ø state 只有类申明的组件中才有

8.4  关于state的深度思考 

(1)  setState为什么设计为异步?

- 如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;
- 最好的办法应该是获取到多个更新,之后进行批量更新

(2)  那么如何可以获取到更新后的值呢?

    方式一:setState的回调

    方式二:在生命周期函数内获取
    
    方式三:异步中

(3)   setState一定是异步吗?

- 在组件生命周期或React合成事件中,setState是异步;
- 在setTimeout或者原生dom事件中,setState是同步;

  		//1. setState 可能是异步更新(有可能是同步更新) 
        this.setState({
            count: this.state.count + 1
        }, () => {
            // 联想 Vue $nextTick - DOM
            console.log('count by callback', this.state.count) // 回调函数中可以拿到最新的 state
        })
        console.log('count', this.state.count) // 异步的,拿不到最新值

        //2. setTimeout 中 setState 是同步的
        setTimeout(() => {
            this.setState({
                count: this.state.count + 1
            })
            console.log('count in setTimeout', this.state.count)
        }, 0)
	
        //3.自己定义的 DOM 事件,setState 是同步的。再 componentDidMount 中
        componentDidMount() {
            // 自己定义的 DOM 事件,setState 是同步的
            document.body.addEventListener('click', this.bodyClickHandler)
        }
       bodyClickHandler = () => {
            this.setState({
                count: this.state.count + 1
            })
            console.log('count in body event', this.state.count)
        }
        componentWillUnmount() {
            // 及时销毁自定义 DOM 事件
            document.body.removeEventListener('click', this.bodyClickHandler)
            // clearTimeout
        }

(4) state可能会被合并如何理解?

		// state 异步更新的话,更新前会被合并 
        // 传入对象,会被合并(类似 Object.assign )。执行结果只一次 +1
        this.setState({
            count: this.state.count + 1
        })
        this.setState({
            count: this.state.count + 1
        })
        this.setState({
            count: this.state.count + 1
        })
        //Object.assign({count:1},{count:1},{count:1})
        // 传入函数,不会被合并。执行结果是 +3
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })
        this.setState((prevState, props) => {
            return {
                count: prevState.count + 1
            }
        })

(5)  关于对象和数组如何实现不可变值操作

	  //不可变值 - 数组
        this.setState({
            list1: this.state.list1.concat(100), // 追加
            list2: [...this.state.list2, 100], // 追加
            list3: this.state.list3.slice(0, 3), // 截取
            list4: this.state.list4.filter(item => item > 100), // 筛选
        })
        // 注意,不能直接对 this.state.list 进行 push pop splice 等,这样违反不可变值

        //不可变值 - 对象
        this.setState({
            obj1: Object.assign({}, this.state.obj1, {a: 100}),
            obj2: {...this.state.obj2, a: 100}
        })

总结:

  • setState->有时异步(普通使用),有时同步(setTimout,dom事件)

  • 有时合并(对象形式 Object.assign),有时不合并(函数形式)

九、 Props进阶

9.1  children属性

children属性,表示组件标签的子节点,当组件标签有子节点时,props就会有该属性,与与普通的props一样,其值可以使任意类型。单标签和双标签中没有数据都是没有此属性。

# 父组件
class App extends React.Component {
  render() {
    return (
        
我是children中的值
) } } # 子组件 {props.children} 获取数据

9.2  类型限制(Props-type)

对于组件来说,props是外部传入的,无法保证组件使用者传入什么格式的数据,简单来说就是组件调用者可能不知道组件封装着需要什么样的数据,如果传入的数据不对,可能会导致程序异常,所以必须要对于props传入的数据类型进行校验。

#安装校验包
npm i -S prop-types

# 在组件中导入
import PropTypes from 'prop-types'


# 函数组件
function App(){}
// 验证规则
App.propTypes = {
    prop-name:PropTypes.string
}

# 类组件
class App extends Component{
    // 类内部完成 检查
    static propTypes = {
       prop-name:PropTypes.string
    }
}

#约束类型
https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html#proptypes
- 类型: array、bool、func、number、object、string
- React元素类型:element
- 必填项:isRequired
- 特定结构的对象: shape({})

React框架基础_第8张图片

 9.3  默认值

如果props没有属性没有传过数据,为了不让程序异常,可以设置其默认值。

# 函数组件
function App(){}

App.defaultProps = {
    title: '标题'
}

# 类组件
class App extends Component {
    static defaultProps = {
        title: '标题'
    }
}

十、表单处理

10.1  受控组件

将state与表单项中的value值绑定在一起,有state的值来控制表单元素的值,称为受控组件。

Ø 在state中添加一个状态,作为表单元素的value值

Ø 给表单元素绑定change事件,将表单元素的值设置为state的值



注:多表单元素需优化事件方法
this.setState({
    username: e.target.value
})

 input textarea select的受控组件案例:

 		// textarea - 使用 value
        return