react菜鸟教程学习笔记

目录

第一个react实例

react安装

对react机制最直观的理解

如果你第一次用npm

关于初始化package.json的问题

使用 create-react-app 快速构建 React 开发环境

项目目录结构

修改一下代码执行源头APP.js

React元素渲染

将元素渲染到DOM中

更新元素渲染

关于vue的更新视图和react更新元素渲染

函数写法

类的写法

关于注意点的解答

关于react算法和vue2与vue3算法比较

React JSX

react实例

注意

使用

独立文件(外连接使用)

关于此时此刻对react和vue的思考

react中封装vue模板语法(参考)

样式

注释

数组

封装组件

函数定义组件(用的多)

关于用ES6 class定义组件(可能因为繁琐,用的少)

注意*

props“内部”传值

属性关键字注意

props父子组件传值

关于细节注意Name name

React State(状态)

前言

React 实例

将生命周期方法添加到类中

生命周期钩子解释

数据自顶向下流动

实例

解析

和dom冒泡操作的关系

和瀑布流的关系

React Props

state 和 props

使用 Props

默认 Props

props实例

Props 验证*

React 16.4 实例

React 15.4 实例

更多验证器内容

vue中处理props

react事件处理(*待深入理解)

关于vue的绑定和react绑定

开始

站在生命周期(钩子函数)有关的角度

vue的事件处理

react条件渲染

元素变量

React 实例

与运算符 &

&

注意

三目运算符

阻止组件渲染*

React 列表 & Keys

重构组件*

Keys*

React API

react组件生命周期

挂载

更新

卸载

react ajax*(实战类待补充)

React 表单与事件(实战重点)

一个简单的实例

实例

实例2*

Select 下拉菜单

多个表单

React Refs(谨慎使用)

使用方法

完整实例

React 实例

vue中ref


第一个react实例

首先是常规的src引入资源链接

<div id="example"></div> <script type="text/babel">   ReactDOM.render(     <h1>Hello, world!</h1>,     document.getElementById('example')   ); </script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
​
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.getElementById('example')
);
</script>
​
</body>
</html>

​​

或者react脚手架下;ES6引入

import React from "react";
import ReactDOM from "react-dom";
​
**function** Hello(props) {
 **return** <h1>Hello World!</h1>;
}
​
ReactDOM.render(<Hello />, document.getElementById("root"));

到这里react给我的印象有点像后端传递给网页标签(数据存放在后端;其实我会想这样做是不是对网站安全,某种程度上;然而确实提供了方便)

react安装

<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script> <!-- 生产环境中不建议使用 --> <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script

对于cdn使用有几点要了解:

这三个要按顺序使用;development开发版本

其中react和react-dom是必须同时引入的,react负责组件创建,react-dom负责DOM渲染。

  1. react和react-dom是必须同时引入的,react负责组件创建,react-dom负责DOM渲染。

  2. development和production版本的区别:- development版本:包含完整的调试信息,大小较大,用于开发环境。

- production版本:移除了调试信息,文件大小较小,用于生产环境。所以在生产环境中应使用production版本,开发环境可以使用development版本。

  1. babel-standalone是可选的,它包含了Babel编译器,可以在浏览器中编译JSX和ES6代码。如果你的代码中使用了JSX或ES6语法,则需要引入babel-standalone。如果代码已经提前编译为普通JavaScript,则可以不引入。

  2. 以上三个库需要按照顺序引入,babel-standalone在最前,react和react-dom之后。

  3. CDN只建议在开发环境使用,生产环境中仍然推荐下载并配置npm版本的React。因为CDN的版本更新不一定及时,也无法自定义配置。

对react机制最直观的理解

如果你第一次用npm

关于初始化package.json的问题

以往都是要先初始化项目出package.json的,今天发现新创建一个项目的时候会自动初始化,好好好😎

使用 create-react-app 快速构建 React 开发环境

跑起来了捏,还自带文档引导,还挺友好🤨

项目目录结构

修改一下代码执行源头APP.js

好像code里的代码默认置后

没看到这里react引用的意义何在,或许是必须的🤔

解答

在这个React代码中,import React, { Component } from 'react';这一行是必不可少的。

原因有:

  1. React是React项目的核心库,没有它jsx语法和组件等都无法使用。

  2. Component是React的基础组件类,我们的App组件继承自它。如果没有导入Component,无法定义组件类。

  3. jsx语法需要React来编译,没有React无法编译jsx,会报错。

修改下入口文件

React元素渲染

我的理解是原生JavaScript在获取dom对象时会返回全部的对象,这对性能是消耗极大的,如果不加以封装,而框架对性能优化的体现就在这里(其中之一)

将元素渲染到DOM中

主要是解释了ReactDOM.render() 的方法的作用和原理;接收react元素

它展示了React的两大核心概念:

  1. 使用JSX创建React元素(表示UI)

  2. 使用ReactDOM.render()将元素渲染到DOM中(展示UI)这也是很多React入门教程和示例的开篇代码。它清晰简明地展示了React的基本工作流程和理念。

更新元素渲染

这里主要讲了react如何实现的“实时更新”,相比vue,react更像是Java开发人员写的(好像是事实哦,因为我印象里定时器和java关系不浅)

通过定时器每时每刻重新渲染局部视图模板(接收函数)

关于vue的更新视图和react更新元素渲染

React和Vue在更新元素渲染方面有以下几点不同:1. React采用虚拟DOM,通过比对新旧虚拟DOM树来更新真实DOM。Vue也使用虚拟DOM,但它是一个观察者,能更精确地更新真实DOM。2. React只有state发生改变时才会更新视图。Vue使用数据绑定,数据发生变化就会更新视图。3. React需要手动调用setState()来更新state和触发重新渲染。Vue的视图是响应式的,数据变化会自动更新。4. React渲染过程为递归比较新旧DOM树。Vue使用依赖跟踪来精确更新视图,较少不必要的DOM操作。5. React的JSX语法需要使用this.state获取状态,要写在render()方法内。Vue的模板可以在data外直接使用data中的数据。更具体来说:在React中:- 调用setState()更新state,触发重新渲染 - state变化会重新执行render(),返回新的JSX元素树 - 新旧JSX元素树会递归比较,更新真实DOM - 只有state发生变化时才会重新渲染在Vue中:- 数据(data)变化会触发依赖更新,精确更新视图 - 响应式数据可以在模板(template)内直接使用 - 数据绑定会监听数据变化,并立即更新视图 - 任何绑定了数据的元素都会更新所以总结来说,React的更新渲染较Vue更精确地依赖state的变化,需要手动触发。Vue的数据绑定使其对数据变化更敏感,可以自动更新视图。但React使用虚拟DOM可以在更新时有更高的性能。两者在理念和使用上有差异,但目的都是高效地渲染UI,开发者可以根据喜好选择使用。掌握了两者的差异,也可以很好地结合使用。

函数写法

将上面要展示的内容封装为函数

解析:

这段代码定义了一个Clock组件和一个tick函数,作用是每秒更新一次Clock组件。具体来说:Clock组件:

jsx
function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>现在是 {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

这是一个函数组件,接受props入参,返回一个JSX元素。它显示一个h1标题和当前时间的h2元素,当前时间来自props.date。tick函数:

jsx
function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('example')
  ); 
}

tick函数每秒调用一次,它使用ReactDOM.render()将Clock组件渲染到DOM中,并传入新的Date对象作为date prop。setInterval(tick, 1000);这行代码使用setInterval()每秒调用一次tick函数。所以总的效果是:每秒渲染一次Clock组件,并显示更新后的当前时间。它通过不断调用ReactDOM.render()来更新组件,实现了类似计时器的效果。

类的写法

需要注意

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('example')
  );
}
 
setInterval(tick, 1000);
关于注意点的解答

在React的类组件中,props是通过this.props访问的。this代表当前的组件实例。从源码角度分析,当React遇到类组件时,它会通过调用该类的构造函数来初始化组件的实例。在构造函数中,会将传入的props属性赋值给this.props。所以在类组件内部,我们通过this.props访问props。例如上面的代码中,Clock组件的构造函数大致如下:

js
constructor(props) {
  super(props);
  this.props = props;  // 将props赋值给this.props
}

然后在render方法中,通过this.props.date来访问date这个prop。如果直接使用props,那么render方法中的this.props.date将找不到props,因为在方法作用域内,没有props这个变量,只有通过this.props可以访问 constructor 中赋值的props。所以在React类组件中,要记住一定通过this.props来读取props,而不是直接props。this代表当前组件实例,通过它可以访问到在构造函数中初始化的属性。总结:1. 类组件中的props通过this.props访问

  1. this代表当前组件实例

  2. 构造函数中会将props赋值给this.props,所以类组件内部通过this.props读取props

关于react算法和vue2与vue3算法比较

React使用diff算法来更新必要的DOM部分。diff算法会比较元素前后两次渲染的不同,并仅更新改变的地方。React的diff算法包含两部分:1. tree diff:比较两棵树(两次渲染的React元素树)的差异,找出需要删除、添加和更新的节点。2. component diff:对相同类型的两个组件进行细致的比较,找出需要更新的props和state。tree diff使用keys来判断两个节点是否相同,如果没有keys,React会使用元素类型和位置来判断相同性,这会导致很多没有必要的DOM操作。而component diff会对相同类型的组件进行props和state的对比,只更新必要变化的地方,这可以提高更新性能。和Vue相比:- Vue 2使用基于路径的虚拟DOM diff算法。它具有O(n^3)的时间复杂度,但在一定程度上避免了不必要的计算,所以在大多数情况下性能还不错。- Vue 3使用基于slot的diff算法,复杂度为O(n)。它采用跨层级比较的方式找出真正需要更新的地方,大大提高了diff的性能。- React的diff算法在时间复杂度和更新精确性上介于Vue 2和Vue 3之间。它采用跨层级比较的方式实现tree diff,但component diff的比较不是那么精确,会导致一定程度的不必要重渲染,所以性能不及Vue 3。总体来说,三者的diff算法都实现了较好的更新性能,但Vue 3的slot diff算法在这个方面是最优的。不过在大多数应用场景下,React和Vue的diff算法都可以满足需求,性能上的差异也不会很大。

.

React JSX

JSX更像是javaweb中的jsp

同样是用来替代常规JavaScript

const element = <h1>Hello, world!</h1>;

react实例

这里我们得知在jsx语法中,可以class命名大致和JavaScript的class命名规则一致

一般JavaScript命名中

var myDivElement = <div className="foo" />;
ReactDOM.render(myDivElement, document.getElementById('example'));

注意

使用

ReactDOM.render+h5标签+获取dom节点并将H5标签渲染到上面

ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.getElementById('example')
);

貌似颠倒下顺序会更符合人的阅读,但一般不这样🤨

独立文件(外连接使用)

建立一个常规命名.js文件,之后jsx代码放在里面,外连接引入编写代码;

使用JavaScript表达式

不能使用if else;但可以三元运算代替

关于此时此刻对react和vue的思考

React的JSX语法在可读性和便利性上不如Vue的模板语法。例如上面那段代码,如果用Vue的模板语法写会是:

html
<div>
  <h1 v-if="i == 1">True!</h1>
  <h1 v-else>False</h1>
</div>

很明显Vue的模板语法更加清晰和易读。这是因为:1. Vue的模板语法更接近HTML,而JSX仍然是JavaScript,需要理解JavaScript的语法和规则。2. Vue的模板语法有指令(如v-if、v-for等)和内置功能(如插槽、动态组件等)可以直接使用,而React需要通过JavaScript实现。3. Vue的模板编译过程会做静态分析、优化和错误检查,而JSX最终还是会被编译为React.createElement()调用,需要开发者自己确保正确使用。4. Vue的模板语法通过扩展可以实现高级功能(如渲染函数),React的JSX始终只是createElement()调用的语法糖。所以,总体来说,Vue的模板语法在开发体验上会更加友好,特别是对于初学者来说,不需要过多理解底层实现,可以更快上手。但这并不意味着React差于Vue。React的JSX也有其优点:1. 更加灵活,可以根据需要组合各种UI元素2. 编码规则和标准JavaScript一致,易于理解3. 有利于将UI和逻辑保持在一起,符合React的设计思想4. 编译后仍然是JavaScript,可以利用现有的工具和规则进行检查、优化和打包等所以,二者都有各自的优缺点。但对于初学者而言,Vue的模板语法会更加友好易上手一些。随着对React理解的深入,JSX的优点也会更加明显。

react中封装vue模板语法(参考)

React本身并没有和Vue模板语法类似的指令或操作码。但我们可以通过自定义Hooks来模拟Vue模板的某些功能。例如,要模拟Vue的v-if指令,可以写一个useTogglehook:

js
function useToggle(initialValue = false) {
  const [state, setState] = useState(initialValue);
  const toggle = () => setState(!state);
  return [state, toggle];
}

然后在JSX中这样使用:

jsx
const [show, toggle] = useToggle(true);
​
return (
  <div>
    {show && <ChildComponent />}
    <button onClick={toggle}>Toggle</button>
  </div>
) 

这就实现了类似v-if的功能。我们也可以写一个useModel来实现v-model:

js
function useModel(initialValue) {
  const [value, setValue] = useState(initialValue);
  const onChange = (e) => setValue(e.target.value);
  return [value, onChange];
}

使用:

jsx
const [text, onChange] = useModel('hello');
​
<input value={text} onChange={onChange} />

这样就可以实现数据双向绑定的效果。类似地,我们可以写自定义Hooks来模拟Vue模板的slot、动态组件、过滤器等功能。React的强大之处在于,它只提供了非常基础的功能,但通过自定义Hooks可以轻易扩展出许多便捷的 abstraction。相比之下,Vue的模板语法自身已经内置了大量便捷的功能,不太鼓励开发者去频繁自定义。这两种方式各有优势,取决于你更偏向于开箱即用还是喜欢自行搭建系统。总之,通过自定义Hooks,React也可以模拟实现Vue模板很多常用的功能。但由于JSX的限制,代码的可读性和语义化还是不及Vue的模板语法。不过,对于React开发者来说,写自定义Hooks来扩展React的本质功能,也是一种提高技能的好方式。

样式

react推荐内联样式

之前就react的这种做法做过分析,在少量的样式下并没什么问题,大概就是没有前端规范的写法;因为实际开发中都是运行即可,前端并不会发挥css这种特殊技能,因此规范这方面只能被忽略了,不然无论是react还是vue框架在规范上都不达标,不合格,但是性能为王,碾压一切...

react会自动在数字后默认添加px,下面实例演示了为h1添加样式

var myStyle = {
    fontSize: 100,
    color: '#FF0000'
};
ReactDOM.render(
    <h1 style = {myStyle}>菜鸟教程</h1>,
    document.getElementById('example')
);

注释

注释需要写在花括号中,这点

ReactDOM.render(
    <div>
    <h1>菜鸟教程</h1>
    {/*注释...*/}
     </div>,
    document.getElementById('example')
);

数组

JSX 允许在模板中插入数组,数组会自动展开所有成员:

var arr = [
  <h1>菜鸟教程</h1>,
  <h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
  <div>{arr}</div>,
  document.getElementById('example')
);

封装组件

接下来我们封装一个输出 "Hello World!" 的组件,组件名为 HelloMessage:

function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}
 
const element = <HelloMessage />;
 
ReactDOM.render(
    element,
    document.getElementById('example')
);

函数定义组件(用的多)

我们可以使用函数定义了一个组件:

function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}

关于用ES6 class定义组件(可能因为繁琐,用的少)

es6还是用的少,没必要添加麻烦

关于es6 class定义组件

在React中,可以使用ES6的class语法来定义组件。例如:

jsx
class Hello extends React.Component {
  render() {
    return <h1>Hello {this.props.name}</h1>;
  }
}

这定义了一个名为Hello的组件类,它扩展了React.Component基类。class组件有以下特点:1. 必须有render()方法,它会返回要渲染的React元素2. 有自己的生命周期方法,可以在组件初始化、更新或销毁时执行某些操作3. 有state和props,它们都可以在class组件中通过this访问4. 可以使用构造函数来初始化state例如:

jsx
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
​
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

这里Clock组件在构造函数中初始化了state,并在render()方法中通过this.state.date读取。除了生命周期方法和state之外,class组件的其他功能与函数组件相同。所以在某些情况下,函数组件的概念会更简单。总结,关于ES6 class定义的React组件,你需要知道:1. 需要扩展React.Component基类2. 必须有render()方法来返回UI元素3. 构造函数可用于初始化state4. 拥有生命周期方法,如componentDidMount()等5. 通过this可以访问state和props6. 除了状态管理和生命周期之外,其他功能与函数组件相同

注意*

const element = <HelloMessage /> 为用户自定义的组件。

注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。

function HelloMessage(props) {
    return <h1>Hello {props.name}!</h1>;
}
 
const element = <HelloMessage name="Runoob"/>;
 
ReactDOM.render(
    element,
    document.getElementById('example')
);

props“内部”传值

在这个示例中,name属性的值"Runoob"被作为props传递给了HelloMessage组件。在HelloMessage组件中,可以通过props.name来访问这个属性。所以,这里的props相当于一个包含所有传入属性的对象。props.name就表示从这个对象中读取name属性的值。这说明:1. 组件的属性通过props对象以键值对的形式传入2. 组件可以通过props访问这些属性的值3. attribute变为对应props对象的一个属性,其值由attribute的值指定4. 因此,props允许父组件有意义地自定义子组件例如,我们可能有:

jsx
<HelloMessage name="John" age={30} />

那么,在HelloMessage组件中可以通过props访问:- props.name = "John" - props.age = 30所以,props允许父组件向子组件传递信息和数据,这是React组件之间通信的一种方式。子组件通过props得到父组件传递过来的信息之后可以根据这些信息渲染不同的内容。在这个示例中,我们把name属性的值"Runoob"作为props传递给了HelloMessage组件,所以在组件内部可以通过props.name访问到这个值,并将其渲染出来。总结:1. 组件通过props得到外部传递过来的信息

  1. props中的每个属性都由组件的属性指定

  2. 组件可以根据props的值来决定渲染什么内容

  3. 这是React组件之间通信的一种方式 - 从父到子

属性关键字注意

注意,在添加属性时, class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。

props父子组件传值

在React中,父组件可以通过props向子组件传递数据或回调方法。这是父子组件之间通信的一种方式。例如,我们有这样的父组件:

jsx
const Parent = () => {
  const handleClick = () => {
    console.log('Clicked!');
  }
  
  return (
    <Child onClick={handleClick} name="John" age={30} />
  )
}

我们向子组件Child传递了:- onClick回调方法 - name和age这两个props在子组件中,可以这样接收:

jsx
const Child = (props) => {
  const { onClick, name, age } = props;
  
  return (
    <div>
      <p>Name: {name} Age: {age}</p>
      <button onClick={onClick}>Click Me</button>
    </div>
  )
}

我们从props对象中解构出onClick、name和age,这些就是父组件传递过来的信息。- onClick可以被绑定到子组件的元素上,当点击按钮时会调用父组件中的方法 - name和age可以在子组件的渲染结果中使用所以,通过props,React组件可以:- 将数据从父组件传递到子组件 - 将事件处理方法从父组件传递到子组件 - 自定义组件的外观和功能对比下不使用props的情况:

jsx
const Parent = () => {
  const handleClick = () => {
    console.log('Clicked!');
  }
  
  return <Child /> 
}
​
const Child = () => {
  return (
    <div>
      <p>Name: John Age: 30</p>
      <button onClick={handleClick}>Click Me</button>  // Error! handleClick is undefined
    </div>
  )
}

在这种情况下,子组件没有办法访问父组件中的handleClick方法,所以onClick绑定会报错。通过props,我们建立了父子组件之间的通信渠道,使子组件得以访问父组件传递过来的各种信息。总结:1. 父组件可以通过props向子组件传递数据和回调方法

  1. 子组件通过props接收父组件传递过来的信息

  2. 子组件可以根据props的值来渲染内容或绑定事件

  3. 这是React组件之间通信的一种方式 - 从父到子

关于细节注意Name name

jsx
<Name name="菜鸟教程" />

里面,Name开头要使用大写字母,而name属性要使用小写字母。这是因为在JSX(React的语法)中,大写开头的元素代表React组件。而小写开头的元素代表HTML内置元素。所以,在这个例子中:- Name是一个自定义的React组件 - name是Name组件的一个props属性如果写成:

jsx
<name name="菜鸟教程" /> 

那么name会被识别为一个HTML元素,而不是React组件,导致错误。而如果写成:

jsx
<NAME NAME="菜鸟教程" /> 

那么NAME和NAME都会被识别为React组件,也会导致错误,因为React组件名必须以大写字母开头。所以,总结来说,在JSX中:- 大写字母开头代表React组件 - 小写字母开头代表HTML内置元素 - React组件的props属性要使用小写字母,遵循camelCase命名这个规则是JSX的语法规定,目的同样是为了提高可读性,让程序员可以清晰地分辨组件、元素和属性。

###

React State(状态)

前言

大体可能想说react是如何在性能上好的;

原本比如下面这个点击自增的按钮例子;

通常原生js会重新渲染整个dom树;

但如果我们劫持了dom,并用算法优化出需要改变的dom部分,只渲染改变的地方,那么性能会好很多

框架起的是这个作用

react 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。

添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。

React 实例

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
 
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
 
ReactDOM.render(
  <Clock />,
  document.getElementById('example')
);
​

将生命周期方法添加到类中

举一个在登录页面开发中使用生命周期钩子的例子:我们有一个登录页面,需要在注册成功或者登录成功后跳转到主页面。并且在离开登录/注册页面前需要清除定时器,否则定时器会继续运行导致内存泄漏。那么我们可以这样编写代码:

jsx
class Login extends React.Component {
  componentDidMount() {
    // 3秒后自动跳转到主页
    this.timer = setTimeout(() => {
      this.props.history.push('/home'); 
    }, 3000);
  }
  
  componentWillUnmount() {
    // 清除定时器
    clearTimeout(this.timer);
  }
  
  // 登录/注册成功,3秒后跳转主页
  onSuccess = () => {
    this.timer = setTimeout(() => {
      this.props.history.push('/home'); 
    }, 3000);
  }
  
  // 跳转主页,同时清除定时器
  goHome = () => {
    clearTimeout(this.timer);
    this.props.history.push('/home'); 
  }
  
  render() {
    // ...
  }
}

在这个示例中,我们在:- componentDidMount 中设置了一个3秒钟跳转到主页的定时器 - componentWillUnmount 中清除了这个定时器,防止内存泄漏 - onSuccess 方法中,登录/注册成功后也设置了一个3秒后跳转主页的定时器 - goHome 方法中,跳转主页的同时清除定时器所以,通过生命周期钩子与定时器的配合,我们完成了:1. 登录/注册页面3秒后自动跳转主页

  1. 登录/注册成功后3秒跳转主页

  2. 无论是手动跳转主页还是离开登录页,定时器都会被清除,避免内存泄漏可以看出,如果没有利用生命周期钩子来与定时器配合,很难完成这样的功能而又不产生内存泄漏的问题。所以,在开发React应用时,特别是包含定时器或异步操作的功能时,充分利用生命周期钩子,可以带来很多好处:1. 避免内存泄漏,防止定时器/异步操作随着组件卸载仍然在运行

  3. 让定时器与组件的 state/props 保持同步

  4. 增加组件的可复用性和稳定性

生命周期钩子解释

componentDidMount()componentWillUnmount() 方法被称作生命周期钩子。

在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。

this.timerID 为定时器的 ID,我们可以在 componentWillUnmount() 钩子中卸载定时器。

代码执行顺序:

  1. <Clock /> 被传递给 ReactDOM.render() 时,React 调用 Clock 组件的构造函数。 由于 Clock 需要显示当前时间,所以使用包含当前时间的对象来初始化 this.state 。 我们稍后会更新此状态。

  2. React 然后调用 Clock 组件的 render() 方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配 Clock 的渲染输出。

  3. Clock 的输出插入到 DOM 中时,React 调用 componentDidMount() 生命周期钩子。 在其中,Clock 组件要求浏览器设置一个定时器,每秒钟调用一次 tick()

  4. 浏览器每秒钟调用 tick() 方法。 在其中,Clock 组件通过使用包含当前时间的对象调用 setState() 来调度UI更新。 通过调用 setState() ,React 知道状态已经改变,并再次调用 render() 方法来确定屏幕上应当显示什么。 这一次,render() 方法中的 this.state.date 将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。

  5. 一旦 Clock 组件被从 DOM 中移除,React 会调用 componentWillUnmount() 这个钩子函数,定时器也就会被清除。

数据自顶向下流动

实例
function FormattedDate(props) {
  return <h2>现在是 {props.date.toLocaleTimeString()}.</h2>;
}
 
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
 
  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
 
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
 
  tick() {
    this.setState({
      date: new Date()
    });
  }
 
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}
 
function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}
 
ReactDOM.render(<App />, document.getElementById('example'));
解析

这段代码中定义了两个组件:1. FormattedDate 组件:- 它接收date作为props - 使用date.toLocaleTimeString()将date格式化为本地时间字符串 - 并渲染到<h2>元素中2. Clock 组件:- 在构造器中初始化state,设置date为当前时间 - 在componentDidMount生命周期钩子中设置定时器,每秒调用tick方法 - 在tick方法中调用setState更新date为当前时间 - 在render方法中渲染<FormattedDate>组件,并将state.date作为props传入 - 在componentWillUnmount中清除定时器,避免内存泄漏3. App组件:- 渲染三个<Clock>组件4. 调用ReactDOM.render将<App>组件渲染到DOM这个代码实现了一个简单的钟表应用,有三个钟同时运行,每秒更新一次时间并重新渲染。这个例子展示了React几个方面的内容:1. 组件生命周期:使用componentDidMount和componentWillUnmount来设置和清除定时器2. 通过this.setState更新组件状态,触发重新渲染3. 父子组件之间通过props传递数据,<Clock>将时间数据传给<FormattedDate>4. 复用同一个组件,这里渲染了三个相同的<Clock>组件5. 利用定时器与生命周期钩子,实现动态渲染效果所以,总的来说,这是一个很好的React小demo,涉及到组件的各个概念与技术点。如果理解这个例子,对学习React有很大帮助。

和dom冒泡操作的关系

这个东西和dom冒泡操作能做对比

自顶向下的数据流和事件冒泡虽然属于React中的两种不同机制,但它们的工作方向是相反的。- 自顶向下的数据流:从父组件流向子组件 - 事件冒泡:从子组件上传向父组件所以,从方向和层级的角度来看,这两种机制是相反的:- 数据流动是自上而下的 - 事件流动是自下而上的但就功能而言,这两种机制在React中协同工作,相互配合:- 父组件通过props传入事件处理函数和state给子组件 - 子组件触发事件,事件沿DOM树冒泡到父组件的事件处理函数 - 父组件的事件处理函数可以通过setState()来更新state,进而更新子组件的props - 实现了父子组件之间的交互与通信所以,更加准确的理解应该是:自顶向下的数据流和事件冒泡在React中属于两种不同的机制,方向相反,但功能上相互配合,共同支撑着组件与组件之间的交互与通信。

和瀑布流的关系

自顶向下的数据流与瀑布流(cascade)没有直接的关系。它们属于两个不同的概念。自顶向下的数据流是React应用中组件之间传递数据的方向。它指:1. 父组件可以通过props将state和方法传递给子组件

  1. 子组件不能直接修改父组件的state

  2. 子组件要通过父组件的方法来间接修改父组件的state

  3. 数据的流动方向是自上而下的,从父组件流向子组件而瀑布流通常指:1. 一个元素中的样式设置会“流动”或“覆盖”到子元素

  4. 子元素可以继承和覆盖父元素的样式

  5. 这种样式的传递会层层递进,就像瀑布一般由上至下所以,从定义来看:- 自顶向下的数据流描述的是React组件树中state和props的传递方向

- 瀑布流描述的是CSS中层叠样式表的样式继承机制它们涉及的层面不同:- 自顶向下的数据流是React的机制,关注组件树和state - 瀑布流是CSS的机制,关注页面样式和继承但是,在React应用的开发中,这两种机制有时也会一起使用,如:1. 父组件设置了样式,这些样式会往下“流动”到子组件

  1. 父组件通过props将样式设置函数传给子组件

  2. 子组件调用这个函数来覆盖或修改父组件设置的样式

  3. 实现了父子组件之间样式的交互和通信所以,总结来说:自顶向下的数据流和瀑布流是两个不同的概念,分属于React和CSS,但在React开发中,它们往往通过props传递等方式协同工作,相互配合。

React Props

state 和 props

在React中,state和props是两个非常重要的概念。理解state和props的区别对学习React有很大帮助。state 和 props 的主要区别有:1. 定义位置不同:- state 定义在组件内部,由该组件维护和控制。 - props 由组件外部传入,由使用该组件的父组件维护和控制。2. 变化方式不同:- state 的值可以在组件内部声明,并通过this.setState()进行更新。 - props 值不能由组件自身进行更新,只能由外部组件更新其值。3. 传递对象不同:- state 传递给组件渲染结果 - props 传递给组件本身4. 可变性不同:- state 的值可以在组件内部变化 - props 的值不可在组件内部变化总结来说:- state是组件内部可变的状态数据,由该组件控制和修改。 - props是从组件外部传入但组件内部不可变的属性数据。举个例子,我们有一个计数器组件:

jsx
class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

在这个组件中:- this.state.count 是组件内部可变的状态数据 - 点击按钮时,调用this.setState()更新state,重新渲染UI现在,如果这个组件的初始count值是通过props传入的,代码如下:

jsx
<Counter count={10} />
​
class Counter extends React.Component {
  render() {
    return (
      <div>
        <p>You clicked {this.props.count} times</p> 
        <button onClick={() => this.setState({ count: this.props.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

在这个例子中,this.props.count 就是从组件外部传入的不可变的props数据。 如果在组件内部直接修改this.props.count,则会报错。所以,props和state虽然都可以决定组件的输出,但它们的用途和特点不同。理解state和props的区别,对学习React和构建组件有很大帮助。

使用 Props

function HelloMessage(props) {
    return <h1>Hello {props.name}!</h1>;
}
 
const element = <HelloMessage name="Runoob"/>;
 
ReactDOM.render(
    element,
    document.getElementById('example')
);

默认 Props

你可以通过组件类的 defaultProps 属性为 props 设置默认值,

props实例
class HelloMessage extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
 
HelloMessage.defaultProps = {
  name: 'Runoob'
};
 
const element = <HelloMessage/>;
 
ReactDOM.render(
  element,
  document.getElementById('example')
);

Props 验证*

暂时不理解用处,

初步理解场景比如:密码框格式,可能会和正则匹配连用

在react16.4和15.4有重大区别

从React 16.4开始,Props验证有一些重要改动。主要的不同在于:16.4之前- 使用propTypes属性来定义 props 验证 - 运行时(runtime)只在开发环境有效 - 发版时需要手动删除propTypes

jsx
Foo.propTypes = {
  bar: PropTypes.number.isRequired
}

16.4及以后- 使用PropTypes作为 import 引入 - 运行时(runtime)在生产环境和开发环境都有效 - 无需删除,直接发布应用即可使用

jsx
import PropTypes from 'prop-types';
​
Foo.propTypes = {
  bar: PropTypes.number.isRequired  
}

此外,16.4后propTypes被重命名为PropTypes,首字母大写。所以,总的来说16.4对props验证主要有以下改动:1. 使用import引入PropTypes,代替直接使用propTypes

  1. 运行时效果由仅开发环境扩展到生产环境

  2. 无需手动删除props验证代码就可以发布生产版本

  3. propTypes属性名改为PropTypes,首字母大写React团队通过这些改动来强调:- props验证应该在开发和生产环境中同时存在

- 开发者们不应该为了性能而删除props验证这有助于开发一组更加健壮和易用的组件

在React中,为了更完整地定义组件,经常需要对传入的props进行验证。这称为props验证。与状态(state)不同的是,由父组件提供的props可能与我们组件期望的不符,所以我们需要验证来保证props的格式和内容。React提供以下两种方式来验证props:1. PropTypes 库React提供了PropTypes库来验证组件的props是否符合要求。使用 PropTypes 最简单的方式就是:

jsx
import PropTypes from 'prop-types';
​
MyComponent.propTypes = {
  name: PropTypes.string,
  age:  PropTypes.number.isRequired
}

这里定义了:- name props 为字符串类型(string) - age props 为必传(isRequired),为数值(number)类型如果父组件提供的props不符合要求,React会发出警告。PropTypes还支持:- array - bool - func - symbol - node - element - object - any等类型,详见文档。2.自定义验证函数我们也可以定义自定义的验证函数:

jsx
validateAge = (props, propName, componentName) => {
  const age = props[propName];
  
  if (age < 18) {
    return new Error(
      '请仅提供年满18岁成年人的姓名。'
    );
  }
}
​
MyComponent.propTypes = {
  name: PropTypes.string,
  age:  validateAge
}

当传入 age < 18 时,React会抛出自定义的错误。总结总的来说,props验证可以:- 定义组件可接收的props类型 - 声明某些props为必传(isRequired) - 注明props的默认值(defaultProps) - 自定义验证函数来满足需要 - 发出警告提示开发者不正确的props用法所有这些都有助于定义功能完备且易于使用的组件。

React 16.4 实例
var title = "菜鸟教程";
// var title = 123;
class MyTitle extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.title}</h1>
    );
  }
}
 
MyTitle.propTypes = {
  title: PropTypes.string
};
ReactDOM.render(
    <MyTitle title={title} />,
    document.getElementById('example')
);

React 15.4 实例
var title = "菜鸟教程";
// var title = 123;
var MyTitle = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },
 
  render: function() {
     return <h1> {this.props.title} </h1>;
   }
});
ReactDOM.render(
    <MyTitle title={title} />,
    document.getElementById('example')
);
更多验证器内容
​
MyComponent.propTypes = {
    // 可以声明 prop 为指定的 JS 基本数据类型,默认情况,这些数据是可选的
   optionalArray: React.PropTypes.array,
    optionalBool: React.PropTypes.bool,
    optionalFunc: React.PropTypes.func,
    optionalNumber: React.PropTypes.number,
    optionalObject: React.PropTypes.object,
    optionalString: React.PropTypes.string,
 
    // 可以被渲染的对象 numbers, strings, elements 或 array
    optionalNode: React.PropTypes.node,
 
    //  React 元素
    optionalElement: React.PropTypes.element,
 
    // 用 JS 的 instanceof 操作符声明 prop 为类的实例。
    optionalMessage: React.PropTypes.instanceOf(Message),
 
    // 用 enum 来限制 prop 只接受指定的值。
    optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
 
    // 可以是多个对象类型中的一个
    optionalUnion: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.number,
      React.PropTypes.instanceOf(Message)
    ]),
 
    // 指定类型组成的数组
    optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
 
    // 指定类型的属性构成的对象
    optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
 
    // 特定 shape 参数的对象
    optionalObjectWithShape: React.PropTypes.shape({
      color: React.PropTypes.string,
      fontSize: React.PropTypes.number
    }),
 
    // 任意类型加上 `isRequired` 来使 prop 不可空。
    requiredFunc: React.PropTypes.func.isRequired,
 
    // 不可空的任意类型
    requiredAny: React.PropTypes.any.isRequired,
 
    // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
    customProp: function(props, propName, componentName) {
      if (!/matchme/.test(props[propName])) {
        return new Error('Validation failed!');
      }
    }
  }
}
​
​

vue中处理props

Vue在处理类似props验证时采用的方式不同于React。首先,Vue中没有单独的props属性来接收来自父组件的数据,而是直接定义在组件的props选项中:

js
Vue.component('child', {
  props: {
    // props 定义
    title: String,
    size: [String, Number]
  }
})

这里定义了titlesize两个prop,分别指定了类型。Vue内置支持以下prop类型:- String - Number - Boolean - Array - Object - Date - Function - Symbol这些 prop 类型会在组件初始化时进行类型检查。此外,Vue还提供以下验证方式:- required 来保证这个 prop 是必传的。 - default 来提供 prop 的默认值。 - validator 用来自定义验证函数。

js
props: {
  title: {
    type: String,
    required: true  
  },
  age: {
    type: Number,
    default: 0,
    validator: value => value >= 0  
  }
}

所以总的来说,Vue中通过:- 在props选项中定义prop - 为每个prop指定类型 - 使用requireddefaultvalidator来实现prop验证这样就实现了与React相似的效果。不同的是,Vue使用的是一个集中的props选项,而不是像React那样有propTypesdefaultProps两个属性。

react事件处理(*待深入理解)

关于vue的绑定和react绑定

- Vue封装了this绑定,开发者直接使用即可 - React需要开发者针对不同情况手动绑定this具体来说:1. Vue中,开发者只需要通过v-on指令将方法绑定到事件监听器上。

html
<button v-on:click="handleClick">按钮</button>
  1. 在方法内部,this会自动绑定到Vue实例。不需要任何手动操作。3. 这是因为Vue封装了事件监听器,内部实现了this的自动绑定。4. 而在React中,开发者需要针对不同情况,自行绑定this:- 在构造函数中绑定

- 使用箭头函数 - 在回调函数中使用.bind(this)5. 因为React没有自动绑定this的机制,需要开发者自行处理。所以,总的来说:- Vue中this绑定是自动的,开发者使用简单方便 - React中this绑定需要开发者针对每种情况手动完成 - 这是因为Vue内部封装了this绑定机制,而React则没有

开始

与原生js区别的命名,react使用驼峰写法(不能算命名)

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

  • React 事件绑定属性的命名采用驼峰式写法,而不是小写。

  • 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)

站在生命周期(钩子函数)有关的角度

只需要在开始添加钩子函数,react监测后自动帮你移除

在React中,你不需要使用像addEventListener这类DOM API为组件添加监听器。而是可以直接在组件的render()或者生命周期钩子中(如componentDidMount)提供监听器。React会智能地在组件渲染或者更新时自动添加或更新相应的事件监听器。举个例子:

jsx
class Button extends React.Component {
  componentDidMount() {
    document.addEventListener('click', this.handleClick);
  }
 
  componentWillUnmount() {
    document.removeEventListener('click', this.handleClick);
  }
 
  handleClick() {
    // ...
  }
}

这里我们确实使用了addEventListenercomponentDidMount中添加了监听器。但是更React的方式是:

jsx
class Button extends React.Component {
  handleClick = () => {
    // ...   
  }
  
  render() {  
    return <button onClick={this.handleClick}>按钮</button>;
  }
}

render()中直接提供一个onClick监听器。React会在组件渲染时自动为这个<button>元素添加事件监听器,调用this.handleClick。在组件卸载时也会自动移除事件监听器。所以说,总的来说,React能帮我们处理:- 在组件初始渲染时自动添加事件监听器 - 在组件更新时更新事件监听器 - 在组件卸载时自动移除事件监听器这点与使用addEventListener不同。所以,在React中通常不需要直接操作DOM来添加事件监听器,只需要在render()或者生命周期函数中提供事件监听器即可。

vue的事件处理

Vue中事件处理的方式与React有一定不同。# Vue中事件处理主要有以下几种方式:1. 使用v-on指令绑定事件监听器:

html
<button v-on:click="doSomething"> </button>

v-on会监听表示所绑定的事件。2. 在methods选项中定义事件处理函数:

js
methods: {
  doSomething: function () {
    // 处理逻辑...
  }
}
  1. 事件处理函数接收一个$event参数:

html
<button v-on:click="doSomething($event)">

$event就是原生DOM事件,可以通过它调用preventDefault等方法。4. 把方法的内联语句简写为:

html
<button @click="doSomething">
  1. 同样支持使用.native修饰符绑定到原生事件:

html
<button @click.native="doSomething">
  1. Vue的自定义事件也使用v-on来监听,并使用$emit触发:

html
<my-component v-on:custom-event="doSomething"></my-component>
js
this.$emit('custom-event')

这就实现了组件间的通信。7. Vue还提供了$on/$off方法在代码中监听/移除事件:

js
this.$on('custom-event', function () {})
this.$off('custom-event')

总的来说,Vue中的事件处理主要通过:- v-on指令绑定事件监听器 - 在methods中定义事件回调函数 - 可以访问原生事件的$event参数 - 使用.native绑定到原生事件 - 通过$emit/$on实现组件间通信它与React的差异主要在于:- Vue不需要在生命周期中添加/移除监听器 - Vue提供了$event参数和.native修饰符访问原生事件 - Vue支持组件间通过自定义事件实现通信

react条件渲染

元素变量

你可以使用变量来储存元素。它可以帮助你有条件的渲染组件的一部分,而输出的其他部分不会更改。

在下面的例子中,我们将要创建一个名为 LoginControl 的有状态的组件。

它会根据当前的状态来渲染 <LoginButton /><LogoutButton />,它也将渲染前面例子中的 <Greeting />

React 实例
class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }
 
  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }
 
  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }
 
  render() {
    const isLoggedIn = this.state.isLoggedIn;
 
    let button = null;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }
 
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}
 
ReactDOM.render(
  <LoginControl />,
  document.getElementById('example')
);

与运算符 &

&

下面这段实例给我最用用的首先是{}存储变量,并且能嵌套(尽管这可能在设计上有些问题,让我联想到node的回调地狱,尽管我经不太清具体内容了🤨)

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          您有 {unreadMessages.length} 条未读信息。
        </h2>
      }
    </div>
  );
}
 
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('example')
);

注意

在 JavaScript 中,true && expression 总是返回 expression,而 false && expression 总是返回 false

因此,如果条件是 true&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。

三目运算符

中规中矩,感觉没啥特别需要区别的

条件渲染的另一种方法是使用 JavaScript 的条件运算符:

condition ? true : false。

在下面的例子中,我们用它来有条件的渲染一小段文本。

render() { const isLoggedIn = this.state.isLoggedIn; return (

The user is {isLoggedIn ? 'currently' : 'not'} logged in.

); } 同样它也可以用在较大的表达式中,虽然不太直观:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

阻止组件渲染*

极少数情况下,你可能希望隐藏组件,即使它被其他组件渲染。

React 列表 & Keys

重构组件*

这个案例可以当成重构,封装组件的学习案例

我们可以使用 JavaScript 的 map() 方法来创建列表。

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
  <li>{numbers}</li>
);
 
ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('example')
);

我们可以将以上实例重构成一个组件,组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
 
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('example')
);

Keys*

一般是数组中id作为key,没有的一般用index(索引)

key常见错误表达

key常见正确表达

元素的 key 在他的兄弟元素之间应该唯一

在 jsx 中嵌入 map()

React API

React api是React为开发者提供的一系列 API 函数和属性,用于构建 React 应用。主要包含以下几个方面:# 组件相关API- React.Component - 创建React组件类 - React.PureComponent - 创建纯组件类 - props - 组件接收属性 - state - 组件内部状态 - setState() - 更新组件状态 - forceUpdate() - 强制组件更新 - render() - 渲染组件# 元素相关API- React.createElement() - 创建 React 元素 - ReactDOM.render() - 渲染元素到 DOM - ReactDOM.hydrate() - 服务器端渲染时使用 - React.Children - 操作子元素# 生命周期钩子- componentDidMount() - componentWillUnmount() - getDerivedStateFromProps() - shouldComponentUpdate() 等# Context API- React.createContext() - 创建 Context对象 - <Context.Provider> - 提供Context对象 - <Context.Consumer> - 消费Context对象# 高阶组件(HOC)- withRouter - 给组件提供路由信息 - authoRize - 鉴权 - withTheme- 动态切换主题等# Fragments- <React.Fragment> - 包裹组件 - <> shorter syntax - 简写# 动画- CSSTransition - CSS 动画 - TransitionGroup - 列表动画 - Transition - 库抽象动画等等,这些都是React所提供的典型API。利用这些功能丰富的API,开发者就可以构建出强大的React应用。

react组件生命周期

建议看文档

挂载

当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下:

  • constructor(): 在 React 组件挂载之前,会调用它的构造函数。

  • getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。

  • render(): render() 方法是 class 组件中唯一必须实现的方法。

  • componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

这些方法的详细说明,可以参考官方文档


更新

每当组件的 state 或 props 发生变化时,组件就会更新。

当组件的 props 或 state 发生变化时会触发更新。组件更新的生命周期调用顺序如下:

  • getDerivedStateFromProps(): 在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。

  • shouldComponentUpdate():当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。

  • render(): render() 方法是 class 组件中唯一必须实现的方法。

  • getSnapshotBeforeUpdate(): 在最近一次渲染输出(提交到 DOM 节点)之前调用。

  • componentDidUpdate(): 在更新后会被立即调用。

render() 方法是 class 组件中唯一必须实现的方法,其他方法可以根据自己的需要来实现。

这些方法的详细说明,可以参考官方文档


卸载

当组件从 DOM 中移除时会调用如下方法:

  • componentWillUnmount(): 在组件卸载及销毁之前直接调用。

这些方法的详细说明,可以参考官方文档

react ajax*(实战类待补充)

React 表单与事件(实战重点)

一个简单的实例

可对比vue的动态渲染(是这么个东西来着🤔)

在实例中我们设置了输入框 input 值 value = {this.state.data}。在输入框值发生变化时我们可以更新 state。我们可以使用 onChange 事件来监听 input 的变化,并修改 state。

实例

class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <input type="text" value={value} onChange={this.handleChange} /> 
            <h4>{value}</h4>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);

实例2*

需要思考一下

在以下实例中我们将为大家演示如何在子组件上使用表单。 onChange 方法将触发 state 的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面。

你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上。

class Content extends React.Component {
  render() {
    return  <div>
            <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} /> 
            <h4>{this.props.myDataProp}</h4>
            </div>;
  }
}
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
  render() {
    var value = this.state.value;
    return <div>
            <Content myDataProp = {value} 
              updateStateProp = {this.handleChange}></Content>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);

Select 下拉菜单

让我想起了学JavaScript时写的很多dom练习;操纵的window对象

在 React 中,不使用 selected 属性,而在根 select 标签上用 value 属性来表示选中项。

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};
 
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
 
  handleChange(event) {
    this.setState({value: event.target.value});
  }
 
  handleSubmit(event) {
    alert('Your favorite flavor is: ' + this.state.value);
    event.preventDefault();
  }
 
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          选择您最喜欢的网站
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="gg">Google</option>
            <option value="rn">Runoob</option>
            <option value="tb">Taobao</option>
            <option value="fb">Facebook</option>
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}
 
ReactDOM.render(
  <FlavorForm />,
  document.getElementById('example')
);

多个表单

当你有处理多个 input 元素时,你可以通过给每个元素添加一个 name 属性,来让处理函数根据 event.target.name 的值来选择做什么

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };
 
    this.handleInputChange = this.handleInputChange.bind(this);
  }
 
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
 
    this.setState({
      [name]: value
    });
  }
 
  render() {
    return (
      <form>
        <label>
          是否离开:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          访客数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

以下实例演示通过 onClick 事件来修改数据:

class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
  
  handleChange(event) {
    this.setState({value: '菜鸟教程'})
  }
  render() {
    var value = this.state.value;
    return <div>
            <button onClick={this.handleChange}>点我</button>
            <h4>{value}</h4>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);

当你需要从子组件中更新父组件的 state 时,你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上。实例如下:

class Content extends React.Component {
  render() {
    return  <div>
              <button onClick = {this.props.updateStateProp}>点我</button>
              <h4>{this.props.myDataProp}</h4>
           </div>
  }
}
class HelloMessage extends React.Component {
  constructor(props) {
      super(props);
      this.state = {value: 'Hello Runoob!'};
      this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({value: '菜鸟教程'})
  }
  render() {
    var value = this.state.value;
    return <div>
            <Content myDataProp = {value} 
              updateStateProp = {this.handleChange}></Content>
           </div>;
  }
}
ReactDOM.render(
  <HelloMessage />,
  document.getElementById('example')
);
​

React Refs(谨慎使用)

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。

这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例。

使用方法

绑定一个 ref 属性到 render 的返回值上:

<input ref="myInput" />

在其它代码中,通过 this.refs 获取支撑实例:

var input = this.refs.myInput;
var inputValue = input.value;
var inputRect = input.getBoundingClientRect();

完整实例

你可以通过使用 this 来获取当前 React 组件,或使用 ref 来获取组件的引用,实例如下:

React 实例

class MyComponent extends React.Component {
  handleClick() {
    // 使用原生的 DOM API 获取焦点
    this.refs.myInput.focus();
  }
  render() {
    //  当组件插入到 DOM 后,ref 属性添加一个组件的引用于到 this.refs
    return (
      <div>
        <input type="text" ref="myInput" />
        <input
          type="button"
          value="点我输入框获取焦点"
          onClick={this.handleClick.bind(this)}
        />
      </div>
    );
  }
}
 
ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

实例中,我们获取了输入框的支撑实例的引用,子点击按钮后输入框获取焦点。

我们也可以使用 getDOMNode()方法获取DOM元素

vue中ref

Ref 在 Vue 和 React 中的意义和用法都比较相似。在 Vue 中,ref 也是用于引用渲染出来的元素或组件实例。使用 ref 的方式主要有:1. 字符串形式:

html
<input ref="hello">

访问:

js
this.$refs.hello
  1. 使用 ref 回调函数:

html
<input ref="hello">

访问:

js
this.hello = ref // 赋值给数据对象
  1. 给组件添加 ref:

html
<ChildComponent ref="child" />

访问:

js
this.$refs.child
​
this.child //如果用了ref回调
  1. 给多元素添加同一个 ref:

html
<input ref="allInputs">
<input ref="allInputs">

这时 $refs.allInputs 会返回一个数组。5. 在 Vue 里使用 ref 是异步的,需要使用 $nextTick:

js
this.$nextTick(() => {
  this.$refs.hello.focus()
})

所以在 Vue 和 React 中:- ref 的作用都是引用渲染出来的元素或组件实例 - 使用方式基本类似,但在实现上存在差异 - 在 Vue 中,ref 是异步引用,需要使用 $nextTick通过将后端数据渲染到前端,ref 在 Vue 和 React 中的使用场景应该是通用的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
React 18是React的最新版本,它引入了一些新的功能和改进。在学习React 18时,你可以关注以下几个方面: 1. React组件:React组件是构建用户界面的基本单元。你可以使用React.createElement()函数或JSX语法来创建React元素和组件。React元素是不可变的,而React组件是可复用的。\[1\] 2. react-dom.development.jsreact-dom/client模块:这些模块提供了处理真实DOM的功能,包括Diff算法和渲染成真实DOM的过程。你可以在HTML文件中引入这些模块,并使用ReactDOM.createRoot()方法来渲染React的DOM。\[2\] 3. Hook:Hook是React中的特殊函数,它允许你在函数组件中添加状态和其他特性。例如,useState是一个Hook,它可以让你在函数组件中添加状态。你可以使用useState来定义和更新状态,并在组件中使用它们。\[3\] 在学习React 18时,你可以通过阅读官方文档、参考教程和实践项目来深入了解这些概念和用法。同时,你也可以与其他开发者交流和分享经验,加深对React的理解。 #### 引用[.reference_title] - *1* *2* *3* [2023年React18笔记【慕课网imooc】【尚硅谷】【Vue3+React18 + TS4考勤系统】](https://blog.csdn.net/qq_28838891/article/details/124598439)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小白村第一深情

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

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

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

打赏作者

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

抵扣说明:

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

余额充值