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开发扩展安装

 五、命令行构建项目

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

 安装成功

 六、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 = (
  <div>
    {/* 我是注释 */}
    {num}
    <hr />
	{/* 三目运算 */}
	{true ? "条件为真" : "条件为假"}
  </div>
)

6.2.2  动态绑定属性

<style>
    /* class 是es6定义类的关键词,在jsx中不能使用,只能通过 className来调用定义好的样式类 */
     button{color:red;}
    .btn{color:red;}
</style>
<script type="text/babel">
const title = '你好世界';
const html1 = '<h3>你好世界</h3>'
    // JSX 语法
    var myh1 = (
     <div>
        {/* class加样式 */}
        <button title={title}>按钮</button>
        <button className="btn">按钮</button>
        {/*# 动态显示html元素*/}
        <div dangerouslySetInnerHTML={{__html: '<a href="">跳转</a>'}}></div>
        <div dangerouslySetInnerHTML={{__html: html1}}></div>
    </div>
    )
    ReactDOM.render(myh1,document.querySelector('#app'));
  </script>
</body>

6.2.3  数组列表渲染

<script type="text/babel">
  let arr = ["张三","李四","王五","赵六"];
  let app = document.getElementById('app');
  ReactDOM.render(
	<div>
 		 {/* jsx中如果是一维数组,直接写上就可以遍历渲染了 */}
      { arr }  
    </div>,
    app
  );
</script>
<script type="text/babel">
    let nameList = ['张三', '李四', '王五'];
    let app = document.getElementById('app');
    ReactDOM.render(
      <div>
        {/* 方案1*/}
        {
            nameList.map((item,index) => {
                return (<h3 key={index}>{item}</h3>)
            })
        }
    
        {/* 方案2 【推荐】*/}
        {
            nameList.map((item,index) => ((
                <h3  key={index}>{item}</h3>
            )))
        }
      </div>,
      app
    );
  </script>

6.2.4  渲染对象列表

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

七、React事件处理

7.1  事件绑定

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

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

onClick onChange

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

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

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

类组件:

函数组件:

 7.2 传值

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

 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 (
      <div>
         <button name="btn" onClick={fn}>点击事件</button>
         <a href="http://www.baidu.com" onClick={fn}>点击事件</a>
      </div>
    )
}
export default Cmp

 合成事件对象

  • 所有事件都挂在到document上

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

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

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指向  <button onClick={this.fun}>按钮</button>
        this.clickHandle = this.clickHandle.bind(this)
    }
    clickHandle(){
        console.log(this);
        console.log('dianji');
    }
    render(){
        return (
            <div><button onClick = {this.clickHandle}>点我点我点我</button></div>
        )
    }
}

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

<button onClick={this.fun.bind(this,参数)}>按钮</button>

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

<button onClick = {(evt) => this.fun(evt,参数)}>按钮</button>

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

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

八、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 (
            <div>计数器 :{this.state.count}</div>
        )
    }
}

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 (
        <div>
          <Cmp>我是children中的值</Cmp>
        </div>
    )
  }
}

# 子组件
{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({})

 9.3  默认值

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

# 函数组件
function App(){}

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

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

十、表单处理

10.1  受控组件

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

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

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

<input type="text" value={this.state.username} onChange={this.inputChange.bind(this)} />

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

 input textarea select的受控组件案例:

 		// textarea - 使用 value
        return <div>
            <textarea value={this.state.info} onChange={this.onTextareaChange}/>
            <p>{this.state.info}</p>
        </div>

        // select - 使用 value
        return <div>
            <select value={this.state.city} onChange={this.onSelectChange}>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
            </select>
            <p>{this.state.city}</p>
        </div>
        onTextareaChange = (e) => {
            this.setState({
                info: e.target.value
            })
        }
        onSelectChange = (e) => {
            this.setState({
                city: e.target.value
            })
        }

checkbox radio受控组件案例:

		// checkbox
        return <div>
            <input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/>
            <p>{this.state.flag.toString()}</p>
        </div>

        // radio
        return <div>
            male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/>
            female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/>
            <p>{this.state.gender}</p>
        </div>
         onCheckboxChange = () => {
            this.setState({
                flag: !this.state.flag
            })
        }
        onRadioChange = (e) => {
            this.setState({
                gender: e.target.value
            })
        }

10.2 非受控组件

没有和state数据源进行关联的表单项,而是借助ref,使用元素DOM方式获取表单元素值

Ø 调用 React.createRef() 方法创建ref对象

Ø 将创建好的 ref 对象添加到文本框中

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

import React, { Component } from 'react'
import FromDemo from './02_FormDemo'
/* 
  ref案例
  liujie  2021-10-20
*/
/*
 1.创建一个ref this.username = React.createRef()
 2.绑定到文本框  ref={ this.username }
 3.获取文本框值  this.username.current.value
 注意:ref获取dom元素 获取组件实例  等同于vue ref
*/
export default class RefDemo extends Component {
    constructor(props){
        super(props)
        this.username = React.createRef()
        this.formcom = React.createRef()
    }
    handerclick = () => {
        console.log(this.username.current);
        console.log('用户名:',this.username.current.value);
        console.log(this.formcom.current.state.radioValue);
        //vue写法 this.refs.myform.value
    }
    render() {
        return (
            <div>
                用户名:<input type="text" ref={ this.username }/>
                <button onClick={ this.handerclick }>登陆</button>
                <FromDemo ref={ this.formcom }/>
            </div>
        )
    }
}

场景:

1.必须手动操作dom元素,setSate实现不了

2.文件上传<input type=file>

3.某些富文本编辑器,需要传入dom元素

受控组件Vs非受控组件:

1.优先使用受控组件,符合react设计原则

2.必须操作dom,在使用非受控组件

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大聪明码农徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值