React教程(React入门教程)(React组件、JSX、React Props、React State、React事件处理、Hooks、高阶组件HOC)

部署运行你感兴趣的模型镜像

文章目录

一、什么是React

React是由Facebook的软件工程师Jordan Walke创建的JavaScript库,于2011年部署于Facebook的newsfeed,2012年部署于Instagram,2013年5月正式开源。React专注于构建用户界面(UI),是MVC框架中的"V"(视图层),而非完整的MVC框架。

React的核心理念是"从UI出发,抽象出不同的组件,继而将它们拼装起来",这顺应了Web开发组件化的趋势。

二、React的特点

1. 组件化:React采用组件化模式,将UI拆分为独立、可复用的组件,提高代码复用率。

2. 声明式设计:React采用声明范式,可以轻松描述应用状态与UI之间的关系。

3. 虚拟DOM:React不直接操作DOM,而是通过虚拟DOM和diff算法,以最小的步骤作用到真实的DOM上,提升性能。

4. 单向数据流:React实现了单向响应的数据流,从数据到视图的渲染,减少了重复代码,比传统数据绑定更简单。

5. 高效:通过对DOM的模拟,最大限度地减少与DOM的交互。

6. 灵活:React可以与已知的库或框架很好地配合。

三、React与其他框架的比较

React与AngularJS等框架的主要区别在于:

- React只专注于MVC框架中的V(视图层),而AngularJS是一个完整的MVC框架。

- React是单向数据流,非双向数据绑定。

参考文章:React单向数据流(unidirectional data flow)与非双向数据绑定的理解

- React不直接操作DOM,而是通过虚拟DOM进行编程。

四、React应用现状

React在国外应用广泛,Facebook、Yahoo、Reddit等知名公司都在使用。在国内,知乎、豆瓣、优酷等大厂也逐渐采用React技术栈。

值得注意的是,截至2022年第一季度,国内前端框架使用上大多偏向于Vue,这导致React前端工程师相对稀缺。在学习难度上,React比Vue稍高,这也是许多企业对React开发经验要求较高的原因。

五、环境搭建

使用create-react-app脚手架快速搭建React项目:

# 创建新项目
npx create-react-app react-project

# 进入项目目录
cd react-project

# 启动项目
yarn start

如果提示没有yarn可看这里:yarn命令介绍(替代npm命令的JavaScript包管理工具)

在这里插入图片描述
在这里插入图片描述

六、React核心概念

1. 组件

React的核心是组件。组件是UI的构建块,可以是类组件或函数组件。

类组件示例

import React, { Component } from 'react'; // 从React库中导入React对象和Component类

class Welcome extends Component { // 定义一个名为Welcome的类组件,继承自React.Component
  render() { // render方法是React组件的核心,用于返回要渲染的UI
    return <h1>Hello, {this.props.name}</h1>; // 返回一个h1元素,显示"Hello,"和传入的name属性
  }
}

函数组件示例

function Welcome(props) { // 定义一个名为Welcome的函数组件,接收props参数
  return <h1>Hello, {props.name}</h1>; // 返回一个h1元素,显示"Hello,"和传入的name属性
}

2. JSX

JSX是JavaScript语法的扩展,使HTML结构与JavaScript代码混合在一起,提高可读性。

const element = <h1>Hello, world!</h1>; // 创建一个h1元素,显示"Hello, world!"

3. Props

Props是组件的属性,用于从父组件向子组件传递数据。

function Welcome(props) { // 定义一个名为Welcome的函数组件,接收props参数
  return <h1>Hello, {props.name}</h1>; // 返回一个h1元素,显示"Hello,"和传入的name属性
}

const element = <Welcome name="Sara" />; // 创建一个Welcome组件的实例,传入name属性为"Sara"

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. State

State是组件内部的状态,用于管理组件的动态数据。

class Counter extends Component { // 定义一个名为Counter的类组件,继承自React.Component
  constructor(props) { // 构造函数,初始化组件状态
    super(props); // 调用父类Component的构造函数
    this.state = { count: 0 }; // 初始化组件状态,count属性初始值为0
  }

  render() { // render方法,返回要渲染的UI
    return (
      <div>
        <p>Count: {this.state.count}</p> // 显示count状态的值
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment // 按钮显示"Increment"
        </button>
      </div>
    );
  }
}

5. 事件处理

React使用事件处理函数处理用户交互。

class Toggle extends Component { // 定义一个名为Toggle的类组件,继承自React.Component
  constructor(props) { // 构造函数,初始化组件状态
    super(props); // 调用父类Component的构造函数
    this.state = { isToggleOn: true }; // 初始化组件状态,isToggleOn属性初始值为true

    // 为确保this指向正确,绑定事件处理函数
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() { // 定义点击事件处理函数
    this.setState(prevState => ({ // 更新状态,使用prevState获取之前的状态
      isToggleOn: !prevState.isToggleOn // 将isToggleOn状态取反
    }));
  }

  render() { // render方法,返回要渲染的UI
    return (
      <button onClick={this.handleClick}> // 按钮的点击事件绑定到handleClick方法
        {this.state.isToggleOn ? 'ON' : 'OFF'} // 根据isToggleOn状态显示"ON"或"OFF"
      </button>
    );
  }
}

疑问:this.handleClick = this.handleClick.bind(this);多余吗?

在 React 类组件中,this.handleClick = this.handleClick.bind(this); 不是多余的,而是必要的。以下是详细解释:


为什么需要绑定?

在 JavaScript 中,类方法默认不会自动绑定 this。当我们将方法作为事件处理函数(如 onClick={this.handleClick})传递时:

  • 事件触发时,handleClick 会被调用,但 this 的指向会丢失(指向 undefinedwindow,取决于上下文)。
  • 例如:this.setState 会因 thisundefined 而报错。

为什么这行代码是必要的?
this.handleClick = this.handleClick.bind(this); // 绑定 this 指向组件实例
  • 作用:确保 handleClick 方法中的 this 指向组件实例(Toggle 的实例)。
  • 如果不绑定this.setState 会失败(thisundefined)。

对比其他写法(为什么这行代码是正确方式)
❌ 错误写法(不绑定):
render() {
  return <button onClick={this.handleClick}>...</button>; // this.handleClick 中的 this 为 undefined
}
✅ 正确写法(构造函数中绑定):
constructor(props) {
  super(props);
  this.state = { isToggleOn: true };
  this.handleClick = this.handleClick.bind(this); // 必须在这里绑定
}
✅ 替代方案(类属性 + 箭头函数,ES7 语法):
class Toggle extends Component {
  handleClick = () => { // 自动绑定 this
    this.setState(...);
  };
  // ...其他代码
}

注意:这是 ES7 语法(类属性),不是类方法。如果使用普通方法(非箭头函数),必须手动绑定


为什么说“不多余”?
  • 性能:在构造函数中绑定一次(this.handleClick = ...)比在 render 中每次渲染都绑定(onClick={this.handleClick.bind(this)}更高效
  • 正确性:确保 this 在组件生命周期中始终指向组件实例。

为什么有人觉得“多余”?
  1. 误解 ES6 类方法:误以为类方法会自动绑定 this实际不会)。
  2. 混淆箭头函数:如果写成 handleClick = () => { ... }(类属性),则无需绑定,但原始代码是普通方法handleClick() { ... }),所以必须绑定。

结论

this.handleClick = this.handleClick.bind(this); 是必要的,不是多余的。
它确保了事件处理函数中的 this 指向组件实例,是 React 类组件的标准实践。

推荐写法(构造函数绑定):

constructor(props) {
  super(props);
  this.state = { isToggleOn: true };
  this.handleClick = this.handleClick.bind(this); // 必须写
}

替代写法(ES7 类属性):

handleClick = () => { // 自动绑定,无需 bind
  this.setState(...);
}

原始代码中的写法是正确且标准的,不是多余的

疑问:为什么 this 会丢失?

在 JavaScript 中,this 的指向取决于函数的调用方式,而不是定义方式。这是理解这个问题的关键。

详细解释
1. 为什么 this 会丢失?(看不懂,尴尬😭测也测不出来。。。)

当我们在 React 中这样写:

<button onClick={this.handleClick}>Toggle</button>

React 实际上是这样调用的:

// 伪代码
button.addEventListener('click', this.handleClick);

当按钮被点击时,React 会调用 this.handleClick,但调用方式是作为普通函数调用,而不是作为对象的方法调用。

在 JavaScript 中:

  • 如果函数是作为对象的方法调用(obj.method()),this 指向 obj
  • 如果函数是作为普通函数调用(method()),this 指向全局对象(浏览器中是 window)或 undefined(严格模式下)

所以当 handleClick 通过 onClick 被调用时:

  • 它不是通过 this.handleClick() 调用的
  • 而是通过 handleClick() 调用的
  • 因此 this 会丢失,指向 undefinedwindow
2. 为什么在构造函数中绑定是正确的方式?
constructor(props) {
  super(props);
  this.state = { isToggleOn: true };
  this.handleClick = this.handleClick.bind(this); // 绑定 this
}

这行代码的作用是:创建一个新的函数,将 this 指向组件实例。这样,无论 handleClick 如何被调用,this 都会指向组件实例。

3. 一个简单示例说明
class Example {
  constructor() {
    this.name = "Example";
    // 不绑定 this
    this.greet = this.greet.bind(this);
  }

  greet() {
    console.log("Hello, " + this.name);
  }

  run() {
    // 普通函数调用
    const fn = this.greet;
    fn(); // 输出: Hello, undefined (this 丢失)
  }
}

const ex = new Example();
ex.run(); // 会输出 "Hello, undefined"

如果我们在构造函数中绑定了 this

constructor() {
  this.name = "Example";
  this.greet = this.greet.bind(this); // 绑定 this
}

那么 fn() 会正确输出 “Hello, Example”。

为什么不是多余的?

在 React 中,事件处理函数的 this 丢失是标准行为,不是 React 特有的问题。这是 JavaScript 语言本身的特性。

  • 如果不绑定,this.setState 会失败(因为 thisundefined
  • 在构造函数中绑定一次,比每次渲染都绑定(如 onClick={this.handleClick.bind(this)}更高效

所以,this.handleClick = this.handleClick.bind(this); 不是多余的,而是 React 类组件中必须的步骤,确保事件处理函数中的 this 指向组件实例。

6. Hooks

React Hooks是React 16.8引入的新特性,允许在函数组件中使用状态和其他React特性。

useState

import React, { useState } from 'react'; // 从React库中导入useState Hook

function Example() { // 定义一个函数组件Example
  // 声明一个名为"count"的state变量,初始值为0
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p> // 显示点击次数
      <button onClick={() => setCount(count + 1)}> // 点击按钮时,将count加1
        Click me
      </button>
    </div>
  );
}

useEffect

import React, { useState, useEffect } from 'react'; // 从React库中导入useState和useEffect Hook

function Example() { // 定义一个函数组件Example
  const [count, setCount] = useState(0); // 声明count状态变量

  // 类似于 componentDidMount 和 componentDidUpdate:
  useEffect(() => { // useEffect Hook,用于在组件渲染后执行副作用
    // 更新文档标题
    document.title = `You clicked ${count} times`; // 设置文档标题为"你点击了count次"
  }, [count]); // 仅在count变化时执行

  return (
    <div>
      <p>You clicked {count} times</p> // 显示点击次数
      <button onClick={() => setCount(count + 1)}> // 点击按钮时,将count加1
        Click me
      </button>
    </div>
  );
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

七、高阶组件

高阶组件(HOC)是React中一个重要的概念,它本质上是一个函数,接收一个组件并返回一个新的增强版组件。

代理方式高阶组件

function withLogger(WrappedComponent) { // 定义一个高阶组件withLogger,接收一个组件作为参数
  return class extends React.Component { // 返回一个新的组件
    componentDidMount() { // 组件挂载完成后执行
      console.log(`Component ${WrappedComponent.name} mounted`); // 在控制台打印组件名称
    }

    render() { // 返回渲染的组件
      return <WrappedComponent {...this.props} />; // 将传入的props传递给被包装的组件
    }
  };
}

使用方式

const EnhancedComponent = withLogger(Welcome); // 使用withLogger高阶组件包装Welcome组件

八、实战:创建一个简单的组件

import React from 'react'; // 从React库中导入React对象
import ReactDOM from 'react-dom'; // 从react-dom库中导入ReactDOM对象

class App extends React.Component { // 定义一个名为App的类组件,继承自React.Component
  constructor(props) { // 构造函数,初始化组件状态
    super(props); // 调用父类Component的构造函数
    this.state = { // 初始化组件状态
      message: 'Hello, React!' // message状态初始值为"Hello, React!"
    };
  }

  handleClick = () => { // 定义点击事件处理函数
    this.setState({ // 更新状态
      message: 'Button clicked!' // 将message状态更新为"Button clicked!"
    });
  }

  render() { // render方法,返回要渲染的UI
    return (
      <div> // 返回一个div容器
        <h1>{this.state.message}</h1> // 显示message状态的值
        <button onClick={this.handleClick}>Click Me</button> // 按钮的点击事件绑定到handleClick方法
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root')); // 将App组件渲染到id为"root"的DOM元素中

九、学习资源推荐

1. 官方文档:React官网提供了最权威的文档和教程。

2. React视频教程:《React极速入门指南》、《Vue、Angular、React 项目开发与深度对比》。

3. 实践项目:通过构建实际项目(如电商网站、社交应用)来巩固知识。

4. 社区支持:React社区活跃,Stack Overflow、GitHub等平台有大量问题解答。

十、结语

React作为当今最流行的前端框架之一,以其组件化、声明式和高性能的特点,成为构建现代Web应用的首选。虽然学习曲线比Vue稍高,但掌握React将为你的前端开发技能带来巨大提升。

随着React生态系统的不断发展(如Redux、React Router、Hooks等),React的应用场景越来越广泛。无论你是前端新手还是有经验的开发者,学习React都将为你的职业发展带来重要价值。

开始你的React之旅,用组件化思维构建更高效、更可维护的Web应用吧!

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Dontla

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

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

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

打赏作者

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

抵扣说明:

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

余额充值