likes
comments
collection
share

从零开始React系列: React核心概念(一)

作者站长头像
站长
· 阅读数 63

项目创建

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

平平无奇的脚手架创建应用, 启动应用的步骤

项目结构

从零开始React系列: React核心概念(一)

public/目录下一般存储公共文件

src/目录下, App.js是初始化生成的组件文件, index.js是React应用的入口文件, reportWevVitals.js在经过查询后得知是页面性能分析工具的配置文件. 下面我们以App.js作为基础文件来学习JSX

JSX

JSX是一种JavaScript语法扩展,用于声明组件的UI层。JSX允许开发人员使用类似HTML的语法来描述应用程序的UI层,使得代码更易于理解和编写。App.js中的代码:

function FirstForJSX() {
  return (
    <div>
      <h1>Now is {new Date().toLocaleTimeString()}</h1>
    </div>
  );
}

export default FirstForJSX;

在这个例子中,我们定义了一个名为FirstForJSX的函数组件,它返回一个JSX表达式。这个表达式描述了一个包含<h1>标签的<div>元素,显示当前时间的文本。

元素渲染

当组件被渲染时,React将使用JSX表达式来创建一个React元素树,该树将被用于构建和更新DOM。

入口文件(index.js)代码如下:

import React from 'react';
import ReactDOM from 'react-dom/client';
import FirstForJSX from './firstForJSX';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <FirstForJSX />
  </React.StrictMode>
);

我们引入了FirstForJSX的组件,它返回一个JSX表达式。

createRoot() 是 React 18 引入的新方法,它用于创建一个根级别的 React 渲染器。与 ReactDOM.render() 不同,createRoot() 方法返回一个新的渲染器对象,该对象具有自己的生命周期和状态。在使用 createRoot() 创建渲染器后,可以使用 render() 方法将 React 组件渲染到 DOM 中。

众所周知, React是单向数据流, 那我们如何在父组件中定义组件中的时间呢?

组件和Props

组件,从概念上类似于 JavaScript 函数。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。举个例子:

function FirstComponent(props) {
  return (
    <div>
      <h1>Now is {props.date}</h1>
    </div>
  );
}

// 或者ES6写法, 注意, 两种写法在这个文件中只能存在一种, 后续我会统一使用ES6写法
class FirstComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Now is {this.props.date}</h1>
      </div>
    );
  }
}

export default FirstComponent;

在这段代码中, 我们在日期显示区域, 使用了props对象

props

props是指组件的属性,它是由父组件传递给子组件的数据。通过props,父组件可以向子组件传递数据和方法,以实现组件间的通信和交互。可以将props想象为组件的输入参数,子组件从父组件接收数据,以便在子组件中进行处理和显示。

在入口文件中, 代码如下:

import FirstComponent from './firstComponent';

// 修改render方法
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <FirstComponent date={new Date().toLocaleTimeString()} />
  </React.StrictMode>
);

官方文档中提到

组件无论是使用函数声明还是通过 class 声明,都绝不能修改自身的 props。

为什么不能修改props? 和Vue的差异?

第一个问题: 为什么

答案其实在上面已经说过了, React是单向数据流, 这是为了保持数据的单一性和可维护性

第二个问题: 和Vue的差异(可能不止以下回答, 我以后再补充)

在Vue中,props是通过子组件的props选项从父组件传递到子组件的。但是,Vue中的数据流动是双向的,这意味着子组件可以修改props的值并将其传递回父组件

既然无法修改props, 那如何在子组件中更新日期呢?

State&生命周期

State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

State

state是一个组件的内部状态,只能通过组件自身的setState方法来改变。通常,React组件中的状态数据是用于控制UI的渲染和交互的。当组件的状态数据发生改变时,React会自动重新渲染组件。感觉跟Vue中的data类似。

下面是个使用了state, componentDidMountcomponentWillUnmount的组件示例, 实现子组件内部更新:

import React from 'react'

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date(),
      timer: null
    }
  }

  componentDidMount() {
    let timer = setInterval(() => {
      this.setState({
        date: new Date()
      })
    }, 10)

    this.setState({
      timer: timer
    })
  }
  componentWillUnmount() {
    clearInterval(this.timer)
  }

  render() {
    return (
      <div>
        <h1>{this.props.prefix} {this.state.date.toLocaleTimeString()}</h1>
      </div>
    );
  }
}

export default Clock

具体来说,新增了以下事情:

  1. 初始化组件的state对象,其中包含了date属性和timer属性,date属性表示当前时间,timer属性表示定时器的ID。
  2. 在组件生命周期方法componentDidMount中,通过setInterval函数每隔10毫秒更新一次组件的状态。在每次更新时,使用this.setState方法更新组件的state对象中的date属性,以此来实现实时更新时钟的功能。
  3. 在组件生命周期方法componentWillUnmount中,清除定时器,以避免内存泄漏。
  4. 在组件的render方法中,根据组件的state和props属性,动态渲染组件的UI,显示当前时间。

在入口文件中, 添加引用和挂载组件:

import Clock from './clock';

// 修改render方法
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Clock prefix="Clock now is" />
  </React.StrictMode>
);

super

super是一个特殊的函数对象,它指向了父类的构造函数。子类的构造函数中必须使用super来调用父类的构造函数,否则子类无法继承父类的属性和方法。

和Vue的异同

  1. React中的state只能通过setState方法来改变,而Vue中的data可以通过直接赋值的方式改变。
  2. React中的state改变后会触发组件重新渲染,而Vue中的data改变后会通过响应式系统自动更新视图。
  3. React中的state可以通过props传递给子组件,而Vue中的data可以通过props和事件传递给子组件。

生命周期

我们在上面的组件中就已经使用到生命周期方法: constructor(props)componentDidMountcomponentWillUnmount:

  • constructor(props): 组件构造函数,用于初始化组件的状态(state)和属性(props)
  • componentDidMount: 在组件已经被渲染到 DOM 中后运行
  • componentWillUnmount: 在组件即将被卸载和销毁之前执行

还有一些常用的生命周期

  1. shouldComponentUpdate(nextProps, nextState):组件更新前调用,用于决定组件是否需要更新,可以通过返回truefalse来控制更新。
  2. componentWillUpdate(nextProps, nextState):组件更新前调用,用于执行一些准备工作,比如保存当前组件状态等。
  3. componentDidUpdate(prevProps, prevState):组件更新后调用,用于执行一些更新后的操作,比如重新渲染DOM、更新组件状态等。
  4. static getDerivedStateFromProps(props, state):这是一个静态方法,用于根据传入的props计算出一个新的state,返回一个对象来更新state。在组件更新前和组件挂载时都会调用这个方法。
  5. getSnapshotBeforeUpdate(prevProps, prevState):组件更新前调用,用于获取更新前的DOM快照,可以在这里进行一些DOM操作,比如滚动到某个位置。
转载自:https://juejin.cn/post/7210639699583746107
评论
请登录