React学习

react的特点

React学习_第1张图片

react 和 vue 的区别

  1. 首先,这两个框架,都是以组件化的思想进行开发的!
  2. 从开发团队上进行对比:
    • React的开发团队,是Facebook官方大牛团队,团队技术实力雄厚;
    • Vue:第一个版本,主要是作者尤雨溪进行维护。
  3. 从社区方面进行对比:
    • React社区早,解决方案多
    • Vue社区晚一点,解决方案相对少一点
  4. 从移动App开发方面:
    • 使用React这门技术,可以分分钟转到ReactNative的开发中
    • VUE 这门技术,也提供了无缝的转移到移动端开发的体验,通过weex可以使用VUE的语法,进行移动端APP开发

脚手架

快速开始

npx create-react-app my-app
cd my-app
npm run start

JSX

JSX嵌套元素

组件中,必须返回一个根元素

如 下列语法是错误的 !

import React, { Component } from 'react'

export default class App extends Component {
  render() {
    return (
      
Hello World!
Hello World!
) } }

假如要想在根目录下直接渲染两个标签,可以使用 Fragment标签,类似 vue中的template

引入Fragment组件

import React, { Fragment } from 'react';

包裹标签

import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';

const App =  ()=> {
  return (
    
      

我就是jsx

我就是jsx

) } ReactDOM.render(, document.getElementById('root'))

JSX表达式

1.普通渲染

我就是jsx

2.数学表达式

{1 + 1}

3.字符串

{'hello world'}

4.bool类型-无法渲染

{isBoy}

5.使用变量

{msg}

6.三目运算符

{isBoy ? "男生" : "女生"}

7.调用方法

const format = (msg) => {
  return '---' + msg + '---';
}    

{format(msg)}

8.使用对象

const lamian = {
  name: "拉面"
};      

{lamian.name}

代码

import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';

const msg = "你们好呀";
const isBoy = false;
const format = (msg) => {
  return '---' + msg + '---';
}
const lamian = {
  name: "拉面"
}; 

const App = () => {
  return (
    
      

我就是jsx

{/* 数字 */}

{1 + 1}

{/* 字符串 */}

{'hello world'}

{/* bool类型 */}

{isBoy}

{/* 使用变量 */}

{msg}

{/* 3目运算符 */}

{isBoy ? "男生" : "女生"}

{/* 调用方法 */}

{format(msg)}

{/* 使用对象 */}

{lamian.name}

) } ReactDOM.render(, document.getElementById('root'))

JSX嵌套语法与循环

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

const msg = "nice 天气";

const App = () => {
  return (
    
{

怎么啦 {msg}

怎么啦 {msg}

}
) } ReactDOM.render(, document.getElementById('root'))

加强版本

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

const list = ['', '', '', ''];


const App = () => {
  return (
    
{
{ list.map(function (v) { return (

{v}

) }) }
}
) } ReactDOM.render(, document.getElementById('root'))

终极版

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

const list = ['苹果', '香蕉', '雪梨', '西瓜'];

const App = () => {
  return (
    
{
{ list.map(v =>

{v}

) }
}
) } ReactDOM.render(, document.getElementById('root'))

JSX注释

{
      // 这里是单行注释
    }
    {
      /*
      这里是多行注释
      这里是多行注释
      这里是多行注释
      这里是多行注释
      */
    }

JSX标签属性

jsx标签上可以设置绝大部分和以前html标签一样的属性,如 checked、图片的src需要注意几个点

  1. htmlclass属性改为className

     
    ☁️
  2. htmllabel标签的for属性改为htmlFor

    
    
  3. 标签中的自定义属性使用data

     
    自定义属性
  4. 渲染 html字符串 使用 dangerouslySetInnerHTML 属性

  5. 来啊呀"}}>
  6. bool类型的值 可以这样用

          
    
  7. 当属性太多了,可以使用 ...扩展运算符

    const props={
      className:"redCls",
      "data-index":5
    }
    
    
    展开属性

JSX的行内样式

JSX可以像传统的HTML标签一样添加行内样式**,不同的是,要通过对象的方式来实现。并且属性名是以驼峰命名。**

import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";

const App = () => {
  return (
    
颜色真不错
) } ReactDOM.render(, document.getElementById('root'))

JSX创建组件的本质 了解

JSX俗称 语法糖,提供了一种更好使用的语法让我们使用,其本质是调用 React.createElement实现的

React.createElement,接收3个参数

  1. 标签名 如 "div"
  2. 标签上的属性,如 {className:"redCls"}
  3. 文本内容或者 另一个 React.createElement对象或者 React.createElement 数组
import React from 'react';
import ReactDOM from 'react-dom';
import "./index.css";

const parentProps = {
  className: "redCls",
  "data-index": 1000
}

const App = () => {
  return React.createElement(
    "div",
    parentProps,
    [
      React.createElement(
        "span",
        null,
        "不错啊呀"
      ),
      React.createElement(
        "span",
        null,
        "真好呀"
      )
    ]
  )
}

ReactDOM.render(, document.getElementById('root'))

1.组件的创建

在react中,组件分为两种,类组件 和 函数式组件

1.简单功能 使用 函数式组件

2.复杂功能 使用 类组件

3.组件名都必须大写

函数式组件

import React from 'react'

export default function App() {
  return (
    
) }

类组件

使用es6创建class的方式来实现一个组件类

1.首字母要大写

2.要继承 React中的Component类

3.必须实现render函数,函数内返回标签

4.组件有自己的state和生命周期

import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import "./index.css";


 class App extends Component {
  render() {
    return (
      
嘿嘿嘿
) } } ReactDOM.render(, document.getElementById('root'))

小结

  • 函数式组件性能更高,因为没有生命周期
  • 函数式组件更方便进行测试
  • 能不用类组件就不用类组件
  • 当要使用 state 时,就要使用类组件

2.状态和属性

React中,状态和属性都可以实现数据动态化

状态 state

在react中,组件内部的数据是通过state来实现和管理

可以理解为state就是Vue中的data

函数式组件没有自己的state

1.state的声明和使用

在类组件中,state的声明分为两种方式

1-1.类属性的方式声明
class Person extends Component {
  // 1 声明 state
  state = {
    date: "2009",
    msg: "天啊天啊"
  }
  render() {
    return (
      
{/* 2 使用state */}

{this.state.date}

{this.state.msg}

) } }
1-2.构造函数中声明
class Person extends Component {
  // 1 构造函数中 声明 state
  constructor() {
    // 1.1 必须在this之前调用super()方法
    super();
    this.state = {
      date: "2009",
      msg: "天啊天啊"
    }
  }
  render() {
    return (
      
{/* 2 使用state */}

{this.state.date}

{this.state.msg}

) } }

2.state的赋值

state的赋值方式通过 this.setState方法 来实现

需要注意的是, 不能 使用 this.state.date= 200 直接修改

class Person extends Component {
  state = {
    date: 2008
  }

  // 2 事件的声明 要使用箭头函数
  handleClick = () => {
    // 3 获取state中的日期
    let { date } = this.state;
    
    // 4 修改state中的日期
    this.setState({
      date: date + 1
    });

  }
  render() {
    return (
      // 1  绑定事件 事件名必须驼峰命名
      

{this.state.date}

) } }

3.state的赋值是异步的

react为了优化性能,将state的赋值代码 改成异步的方式,可以避免反复的设置state而引发的性能损耗问题。

看看下面打印的值

class Person extends Component {
  state = {
    date: 2010
  }
  handleClick = () => {
    let { date } = this.state;

    // 1 修改state中的日期 增加 2000
    this.setState({
      date: date + 2000
    });

    // 2 此时这个date还是2010而不是4010
    console.log(this.state.date);
  }
  render() {
    return (
      

{this.state.date}

) } }

有时候,我们希望在一设置值的时候,就希望马上得到最新的state的值,那么可以将代码改为下列的写法

setState添加一个回调函数,回调中可以获取到修改后的state的值

class Person extends Component {
  state = {
    date: 2008
  }

  handleClick = () => {
    let { date } = this.state;

    // 添加一个回调函数
    this.setState({
      date: date + 3000
    }, () => {
      // date的值为 5008
      console.log(this.state.date);
    });
  }
  render() {
    return (
      

{this.state.date}

) } }

有时候,setState还可以接收一个函数,函数内可以实时获取state中的值,不存在延迟

this.setState(preState => {
    console.log("上一次的state", preState.date);
    return {
        date: preState.date + 1000
    }
})

属性 props

props意思是属性,一般存在 父子组件中。用于 父向子传递数据

子组件不能修改接收到的props值

1.声明一个类组件 HomeTop 父组件的数据通过 this.props 来获取

class HomeTop extends Component {
  render() {
    return (
      

屋顶的颜色是 {this.props.acolor} 尺寸 {this.props.asize}

) } }

2.声明一个函数式组件HomeFooter,父组件传递的数据 需要在函数的形参props上接收

const HomeFooter = (props) => {
  return 

屋底的颜色是 {props.bcolor} 尺寸 {props.bsize}

}

3.声明父组件,并在标签上通过属性的方式进行传递数据

class Home extends Component {
  state = {
    color: "blue",
    size: 100
  }
  render() {
    return (
      
) } }

完整代码

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class HomeTop extends Component {
  render() {
    return (

      

屋顶的颜色是 {this.props.acolor} 尺寸 {this.props.asize}

) } } const HomeFooter = (props) => { return

屋底的颜色是 {props.bcolor} 尺寸 {props.bsize}

} class Home extends Component { state = { color: "blue", size: 100 } render() { return (
) } } ReactDOM.render(, document.getElementById('root'))

类组件构造函数中的props

当想要在类组件的构造函数中,获取到props时,需要如下使用

constructor(props) {
    super(props);
    console.log(props);
}

props默认值

当父元素没有传递props属性时,子组件可以指定一个默认props属性值来使用。

通过 组件名.defaultProps 来指定

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

let HomeNav = (props) => {
  return 

导航为 {props.color}

// 或者 static defaultProps = { color: "yellow" } } // 指定一个默认属性 HomeNav.defaultProps = { color: "yellow" } class Home extends Component { state = { color: "blue" } render() { return (
) } } ReactDOM.render(, document.getElementById('root'))

props类型校验

在一些要求代码更为严格的项目中,父组件传递数据的格式,必须和子组件要求的格式保持一致,否则就认为代码出错

自 React v15.5 起,React.PropTypes 已移入另一个包中。请使用 prop-types 库 代替

安装 prop-types
npm install prop-types --save
引入
import PropTypes from 'prop-types'; 
使用
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// 1 引入 prop-types
import PropTypes from 'prop-types'; 


let HomeNav = (props) => {
  return 

导航为 {props.color} 数量为 {props.nums}

} // 2 指定要求接收的数据格式 HomeNav.propTypes ={ color:PropTypes.string, nums:PropTypes.number } class Home extends Component { state = { color: "blue", nums:100 } render() { return (
) } } ReactDOM.render(, document.getElementById('root'))

props插槽 props.children

props.children可以实现类似vue中的插槽功能

子组件
let HomeNav = (props) => {
  return (
    
标题
{props.children}
) }
父组件
class Home extends Component {
  render() {
    return (
      
{/* 这里放动态插入的内容 */}
在这个父组件中的子组件内插入一个div包含的内容,需要在子组件中{props.children}才能显示
) } }
完整代码
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

let HomeNav = (props) => {
  return (
    
标题
{props.children}
) } class Home extends Component { render() { return (
{/* 这里放动态插入的内容 */}
在这个父组件中的子组件内插入一个div包含的内容,需要在子组件中{props.children}才能显示
) } } ReactDOM.render(, document.getElementById('root'))

state 和 props 对比

相同

1.二者都作为 React 内更新视图的依据,只有它们变化时,React 才会进行相应的更新。

2.二者都不可以通过直接赋值的方式更新。

不同

1.更新方式不同:state 通过 setState 方法更新(只能在组件内部更新),props 则通过更新传入的值实现(组件内不可变)。

2.state 只维护组件内部的状态,props 让外部维护组件的状态。

总结

尽量少用state,尽量多用props,这样既能提高组件的可复用性,又能降低维护成本

事件

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

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

传统HTML绑定事件

<button onclick="activateLasers()">
  Activate Lasers
button>

React中


事件中的this

观察以下的this的值 它是undefined

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Home extends Component {
  state = {
    msg: "大家好呀"
  }
  handleClick() {
    // undefined
    console.log(this);
  }
  render() {
    return (
      
小标题
) } } ReactDOM.render(, document.getElementById('root'))

因为在react中,绑定事件 不是原生HTML的dom元素,onClick只是react帮我们做的一个中间的映射,那么它在处理事件的时候,是不会处理this的指向的,需要我们手动处理这个this

处理方式

1.绑定事件的时候 使用bind来锁定this

小标题

2.在构造函数中 使用bind修改 this指向

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Home extends Component {
  state = {
    msg: "大家好呀"
  }
  constructor() {
    super();
    // 重新绑定this
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log(this);
  }
  render() {
    return (
      
小标题
) } } ReactDOM.render(, document.getElementById('root'))

**3.将事件的执行,改成 箭头函数 的方式 **

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Home extends Component {
  state = {
    msg: "大家好呀"
  }
	// 修改为箭头函数的方式
  handleClick = () => {
    console.log(this);
  }
  render() {
    return (
      
小标题
) } } ReactDOM.render(, document.getElementById('root'))

事件传参

执行类似以前HTML的dom事件传参一样的功能


React中的写法

1.不推荐,容易导致意外情况


2.推荐写法


受控和非受控表单

受控是指受React控制。可以理解为绑定了value或者checked属性的表单就是受控表单。也可以理解为受控表单就是实现了双向绑定。

受控表单

input标签和checkbox标签进行改造

input 受控

必须同时给与 onChange事件和绑定value属性


逻辑中 执行给 inpValue赋值

handleChangeValue(e) {
    this.setState({
      inpValue: e.currentTarget.value
    })
  }

checkbox 受控

必须同时给与 onChange事件和绑定value属性


逻辑中 执行给 inpValue赋值

handleChkChecked(e){
    this.setState({
        isChecked:e.currentTarget.checked
    })
}

更多受控标签的说明

元素 绑定事件 h获取值
value="string" onChange event.target.value
checked={boolean} onChange event.target.checked
checked={boolean} onChange event.target.checked