从零开始React系列: React核心概念(一)
项目创建
npx create-react-app my-app
cd my-app
npm start
平平无奇的脚手架创建应用, 启动应用的步骤
项目结构
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
, componentDidMount
和componentWillUnmount
的组件示例, 实现子组件内部更新:
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
具体来说,新增了以下事情:
- 初始化组件的state对象,其中包含了date属性和timer属性,date属性表示当前时间,timer属性表示定时器的ID。
- 在组件生命周期方法componentDidMount中,通过setInterval函数每隔10毫秒更新一次组件的状态。在每次更新时,使用this.setState方法更新组件的state对象中的date属性,以此来实现实时更新时钟的功能。
- 在组件生命周期方法componentWillUnmount中,清除定时器,以避免内存泄漏。
- 在组件的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的异同
- React中的state只能通过setState方法来改变,而Vue中的data可以通过直接赋值的方式改变。
- React中的state改变后会触发组件重新渲染,而Vue中的data改变后会通过响应式系统自动更新视图。
- React中的state可以通过props传递给子组件,而Vue中的data可以通过props和事件传递给子组件。
生命周期
我们在上面的组件中就已经使用到生命周期方法: constructor(props)
、componentDidMount
、componentWillUnmount
:
constructor(props)
: 组件构造函数,用于初始化组件的状态(state)和属性(props)componentDidMount
: 在组件已经被渲染到 DOM 中后运行componentWillUnmount
: 在组件即将被卸载和销毁之前执行
还有一些常用的生命周期
shouldComponentUpdate(nextProps, nextState)
:组件更新前调用,用于决定组件是否需要更新,可以通过返回true
或false
来控制更新。componentWillUpdate(nextProps, nextState)
:组件更新前调用,用于执行一些准备工作,比如保存当前组件状态等。componentDidUpdate(prevProps, prevState)
:组件更新后调用,用于执行一些更新后的操作,比如重新渲染DOM、更新组件状态等。static getDerivedStateFromProps(props, state)
:这是一个静态方法,用于根据传入的props计算出一个新的state,返回一个对象来更新state。在组件更新前和组件挂载时都会调用这个方法。getSnapshotBeforeUpdate(prevProps, prevState)
:组件更新前调用,用于获取更新前的DOM快照,可以在这里进行一些DOM操作,比如滚动到某个位置。
转载自:https://juejin.cn/post/7210639699583746107