快速掌握 React 基础入门: 一个完整的指南(一)https://developer.aliyun.com/article/1426132
D. JSX 中的表达式
在 JSX 中,可以通过花括号 {}
来引用 JavaScript 表达式,从而可以动态渲染组件内容。
例如,我们可以通过引用一个变量来动态显示一个组件的内容:
import React from 'react'; function Greeting(props) { const name = props.name; return <div>Hello, {name}!</div>; } function App() { const name = 'Alice'; return <Greeting name={name} />; } export default App;
在这个示例中,Greeting
组件接收一个 name
属性,将其插入到字符串中来动态生成问候语。而在 App
组件中,我们定义了一个名为 name
的变量,并将其作为 Greeting
组件的 name
属性进行传递。
在 JSX 中,我们可以在花括号中使用任意的 JavaScript 表达式,例如:
import React from 'react'; function Greeting(props) { return <div>{props.isActive ? 'This user is active' : 'This user is not active'}</div>; } function App() { const isActive = true; return <Greeting isActive={isActive} />; } export default App;
在这个示例中,我们使用一个带有三目运算符的 JavaScript 表达式来动态地渲染 Greeting
组件中的内容,根据传入的 isActive
属性来判断当前用户是否处于活跃状态。
需要注意的是,在 JSX 中,只能引用 JavaScript 表达式,而不能引用语句或代码块。因此,不能在花括号中使用诸如 if
、for
、switch
等控制流语句,只能使用简单的表达式或函数调用来完成相应的逻辑。
V. State 和 Props
A. 概述
React 中有两种常用的数据流:props
和 state
。
Props
是组件之间通信的一种方式,是从父组件向子组件传递数据的方式。
props
是只读的,不能在组件内部修改。父组件可以随时更改 props 的值,因此,它是一种“单向数据流”的模式,即数据从上层组件流向下层组件。
例如,我们可以通过 props 来传递一些参数或回调函数给子组件,从而控制子组件的行为和显示:
import React from 'react'; function ChildComponent(props) { return ( <div> <p>{props.title}</p> <button onClick={props.onClick}>Click me</button> </div> ); } function ParentComponent(props) { function handleClick() { console.log('Button clicked!'); } return <ChildComponent title="Hello World!" onClick={handleClick} />; } export default ParentComponent;
在这个示例中,我们将一个名为 title
的字符串和一个名为 onClick
的回调函数作为 props 传递给了子组件 ChildComponent
,从而控制子组件的标题和按钮行为。
State
则是组件内部自身管理的一种数据。它能够让组件根据不同的外部条件渲染出不同的结果。和 props 不同,state 可以在组件内部修改,并且修改 state 会重新渲染组件。在 React 组件中,每当 state 或 props 发生变化时,React 会自动重新渲染组件。
例如,我们可以使用 state 来控制组件在不同的状态下渲染不同的结果:
import React, { useState } from 'react'; function MyComponent(props) { const [isActive, setIsActive] = useState(false); function handleClick() { setIsActive(!isActive); } return ( <div> <p>{props.title}</p> <button onClick={handleClick}> {isActive ? 'Active' : 'Not Active'} </button> </div> ); } export default MyComponent;
在这个示例中,我们定义了一个名为 isActive
的 state,并在按钮的点击事件中修改它的值来控制按钮显示内容的变化。当我们点击按钮时,组件的 state 发生变化,React 会自动重新渲染组件,从而实现按钮内容的切换。
总体来说,props 和 state 是 React 组件中最常用的两种数据流,它们在组件之间和组件内部分别扮演着不同的角色,帮助我们实现复杂的前端功能。
B. State
在 React 中,state 表示组件内部的状态。每个组件都可以定义自己的 state,并根据 state 的值来渲染 UI 界面。如果某个组件的 state 发生了变化,React 会自动重新渲染组件,并将新的 state 值传递给组件重新渲染。
在类组件中,我们可以通过定义构造函数来初始化组件的 state,例如:
import React, { Component } from 'react'; class MyComponent extends Component { constructor(props) { super(props); this.state = { count: 0, }; } render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Increment </button> </div> ); } } export default MyComponent;
在这个示例中,我们定义了一个名为 count
的 state,初始值为 0,在组件的 render
方法中用来渲染计数器和按钮。当我们点击按钮时,会调用 setState
方法来修改 state 值,从而触发组件的重新渲染。
需要注意的是,在 React 中,不要直接修改 state 的值,而是应该使用 setState
方法来修改 state。因为 setState
方法不仅会更新 state,还会触发组件重新渲染,从而保证 UI 的一致性。
另外,由于 state 只能在类组件中使用,如果我们需要在函数式组件中管理状态,可以使用 useState
钩子函数来定义 state,例如:
import React, { useState } from 'react'; function MyComponent(props) { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); } export default MyComponent;
在这个示例中,我们使用 useState
钩子函数来声明名为 count
的 state,初始值为 0,通过调用 setCount
方法来修改 state 值。这样,就可以在函数式组件中管理组件的状态了。
C. Props
在 React 中,props 是一种用来传递数据的机制,用途类似于参数传递。通过 props,我们可以将父组件的数据传递给子组件,从而实现组件之间的通信。
在函数组件中,props 是函数的参数,例如:
import React from 'react'; function MyComponent(props) { return <div>{props.message}</div>; } export default MyComponent;
在这个示例中,我们定义了一个名为 message
的 props,并在组件中使用它来渲染文本。当我们在父组件中使用 时,传递给子组件的 props 中就包含了一个名为
message
,值为 “Hello World” 的属性。
在类组件中,我们可以通过 this.props
来访问成员变量,例如:
import React, { Component } from 'react'; class MyComponent extends Component { render() { return <div>{this.props.message}</div>; } } export default MyComponent;
这里的 this.props
是一个对象,包含了传递给组件的所有 props 属性。我们可以通过 this.props
来访问这些属性,并在组件中使用它们来渲染 UI。
需要注意的是,props 是只读的,不应该在子组件中直接修改 props 的值。如果需要修改组件的状态,应该定义自己的 state,并通过回调函数来实现从父组件向子组件传递数据。
例如,我们可以通过定义一个回调函数 onButtonClick
来向父组件传递按钮点击事件的信息:
import React, { Component } from 'react'; class MyComponent extends Component { handleClick = () => { this.props.onButtonClick('Button clicked!'); } render() { return ( <div> <button onClick={this.handleClick}>Click me</button> </div> ); } } export default MyComponent;
在这个示例中,我们定义了一个名为 onButtonClick
的回调函数,并在按钮的点击事件中调用它来向父组件传递信息。父组件可以通过传递一个回调函数来接收这个信息:
import React, { Component } from 'react'; import MyComponent from './MyComponent'; class App extends Component { handleButtonClick = (message) => { console.log(message); } render() { return ( <div> <MyComponent onButtonClick={this.handleButtonClick} /> </div> ); } } export default App;
在这个示例中,我们在父组件中定义了一个名为 handleButtonClick
的回调函数,并将它作为 onButtonClick
属性传递给了子组件 MyComponent
。当子组件的按钮被点击时,它会调用 onButtonClick
方法,并将消息传递给父组件。父组件接收到消息后,可以在控制台中输出这个消息。
VI. 事件处理
A. 事件绑定
在 React 中,事件绑定和处理与传统的 HTML 相比有些不同。这是因为在 React 中,事件处理是基于虚拟 DOM 实现的,需要在组件中定义事件处理器,并将它们绑定到 UI 元素上。
在 React 中,我们可以使用 onClick
、onMouseOver
、onChange
等事件绑定函数来绑定事件,例如:
import React, { Component } from 'react'; class MyComponent extends Component { handleClick = () => { console.log('Button clicked!'); } handleMouseOver = () => { console.log('Mouse over!'); } handleChange = (event) => { console.log('Input value:', event.target.value); } render() { return ( <div> <button onClick={this.handleClick} onMouseOver={this.handleMouseOver}>Click me</button> <input type="text" onChange={this.handleChange} /> </div> ); } } export default MyComponent;
在这个示例中,我们定义了三个名为 handleClick
、handleMouseOver
和 handleChange
的事件处理函数,并将它们绑定到了按钮和输入框上。当按钮被点击、鼠标经过或输入框的值发生变化时,相应的事件处理函数就会被触发。
需要注意的是,在事件处理函数中不能使用 this
来访问组件的成员变量,因为事件处理函数默认是在全局作用域下执行的,this
指向全局对象。如果需要访问组件的成员变量,可以将事件处理函数定义为箭头函数或使用 bind
方法绑定 this
指向。
例如,这里我们使用箭头函数来定义事件处理函数:
import React, { Component } from 'react'; class MyComponent extends Component { state = { count: 0 }; handleClick = () => { this.setState({ count: this.state.count + 1 }); } render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.handleClick}>Increment</button> </div> ); } } export default MyComponent;
在这个示例中,我们定义了一个名为 count
的 state,并在按钮的点击事件中使用箭头函数来修改 state 值。这样,就可以在事件处理函数中访问组件的成员变量了。
B. 事件对象
事件处理函数的参数中会自动传入一个 event
(也可以自定义名称)事件对象,用它可以获取触发事件的相关信息,如 target
, currentTarget
, clientX
等等。
event.target
:获取触发事件的元素,即事件的发出者。比如button
或者div
等。event.currentTarget
:获取所有被绑定事件的元素,即事件绑定的发生元素。比如事件被绑定在div
上,那么currentTarget
获取的是这个div
。event.preventDefault()
:阻止默认行为,例如禁止某个元素的链接跳转或表单提交。event.stopPropagation()
:停止事件冒泡,即当某个元素上触发事件时,该事件不会向上层的元素进一步传播。
示例:
import React from 'react'; function MyComponent() { function handleClick(e) { console.log(e.target); console.log(e.currentTarget); e.preventDefault(); e.stopPropagation(); } return ( <div> <a href="https://google.com" onClick={handleClick}> Click me </a> <button onClick={handleClick}>Button</button> </div> ); } export default MyComponent;
在这个例子中,我们定义了一个名为 handleClick
的事件处理函数,并将它绑定到两个 UI 元素(a
和 button
)的点击事件上。当用户点击这两个元素时,会触发 handleClick
方法,并传入一个名为 e
的事件对象。我们可以使用 e.target
和 e.currentTarget
来获取触发事件的元素和绑定事件的元素,并使用 e.preventDefault()
和 e.stopPropagation()
阻止默认行为和事件冒泡。
C. setState
setState
是 React 中一个非常常用的方法,用来更新组件的状态。
在类组件中,setState
是 Component
类的一个成员函数,通过调用 setState
方法,我们可以更新组件的状态,并触发组件的重新渲染。
setState
有两种使用方式:
- 第一种是传入一个对象,用来更新部分状态,例如:
this.setState({ count: this.state.count + 1 });
- 在这个例子中,我们使用
setState
方法来更新count
状态,将它的值增加 1。通过传入一个对象,我们可以只更新部分状态,而不必更新整个状态对象。 - 第二种是传入一个函数,函数的第一个参数是前一个状态,返回一个对象,用来更新状态,例如:
this.setState((prevState) => ({ count: prevState.count + 1 }));
- 在这个例子中,我们使用函数作为
setState
的参数,传入一个名为prevState
的参数,表示前一个状态对象。函数返回一个对象,用来更新状态。通过传入一个函数,我们可以避免出现更新时的竞态条件(race condition)。
需要注意的是,由于 setState
是异步的,因此如果在 setState
中读取 this.state
的值,可能会得到不准确的结果。如果需要在 setState
后执行一些操作,可以将操作放入 setState
的第二个参数中,例如:
this.setState({ count: this.state.count + 1 }, () => { console.log('Count updated to:', this.state.count); });
在这个例子中,我们将一条输出语句放入 setState
的第二个参数中,当状态更新完成后,输出语句就会被执行。
另外,由于 setState
的机制是异步的,如果我们需要在多个状态更新操作完成后才执行一些操作,可以使用 componentDidUpdate
生命周期函数来处理。在 componentDidUpdate
中可以检查当前状态是否符合预期,并执行一些操作。
VII. 生命周期
A. 概述
在 React 组件中,有许多生命周期函数可以用来在不同的时间点执行各种操作。生命周期函数可以帮助我们在组件的不同阶段进行一些初始化、渲染、更新、卸载等操作,控制整个组件的行为和外部交互。
React 组件的生命周期可以分为三个阶段:
- 挂载阶段(Mounting):组件实例被创建,插入到 DOM 中,完成了组件的第一次渲染。
- 更新阶段(Updating):组件被重新渲染,可能由于 props 或 state 发生改变产生更新,也可能由于 forceUpdate() 触发更新。
- 卸载阶段(Unmounting):组件从 DOM 中移除,销毁组件实例,释放相关资源。
在每个阶段,React 会自动调用相应的生命周期函数,我们可以在这些函数中实现特定的操作。
具体来说,React 组件的生命周期函数包括以下函数:
constructor(props)
:构造函数,用来初始化组件的状态和绑定成员函数的 this 指向。getDerivedStateFromProps(props, state)
:静态函数,用来更新组件状态,返回新的 state 对象或 null。通常用来在 props 发生变化时更新 state。render()
:渲染函数,用来生成组件的虚拟 DOM。componentDidMount()
:挂载函数,用来进行组件的初始化操作,例如网络请求、定时器等。shouldComponentUpdate(nextProps, nextState)
:更新函数,用来判断组件是否需要更新。返回一个布尔值,表示是否需要更新。默认返回 true,即总是更新。getSnapshotBeforeUpdate(prevProps, prevState)
:静态函数,用来获取更新前的 DOM 快照。返回一个快照对象或 null。通常用来在组件更新前保存一些 DOM 状态,并在更新后恢复状态。componentDidUpdate(prevProps, prevState, snapshot)
:更新函数,用来进行组件更新后的操作,例如重新计算 DOM 元素的位置、滚动条位置等。componentWillUnmount()
:卸载函数,用来进行组件的清理操作,例如取消订阅、清除定时器等。
还有一些其他的生命周期函数,不过它们有些是过去时态,已经废弃或者不建议使用了,如componentWillMount()
, componentWillReceiveProps()
等。
B. Mounting 阶段
Mounting 阶段是指 React 组件被实例化,并将组件的虚拟 DOM 渲染到实际的 DOM 中的过程。
在 Mounting 阶段,React 会自动调用以下生命周期函数(按照调用顺序):
constructor(props)
:构造函数,在此函数中可以初始化组件的状态。static getDerivedStateFromProps(props, state)
:静态函数,该函数会在虚拟 DOM 处理之前被调用,用于更新组件的状态。通常情况下,推荐根据传入的props
来更新组件的state
,并返回更新后的state
。如果不需要更新状态,则返回null
。render()
:渲染函数,返回组件的虚拟 DOM,用来显示在页面上。componentDidMount()
:挂载函数,组件被挂载到实际的 DOM 树上后调用,此时可以进行一些网络请求、订阅事件等操作。
示例代码:
import React, { Component } from 'react'; class Example extends Component { constructor(props) { super(props); this.state = { value: 'Hello World' }; } static getDerivedStateFromProps(props, state) { console.log('getDerivedStateFromProps', props, state); return null; } componentDidMount() { console.log('componentDidMount'); } render() { console.log('render'); return ( <div> <p>{this.state.value}</p> </div> ); } } export default Example;
在这个例子中,我们定义了一个名为 Example
的组件,并在其中实现了 constructor
、getDerivedStateFromProps
、componentDidMount
以及 render
函数。在 constructor
中,我们初始化了组件的 state
,并在 render
函数中将 state
的值显示在了页面上。在 getDerivedStateFromProps
和 componentDidMount
函数中,我们分别输出了一些信息,用于演示生命周期函数的调用顺序。
当使用 Example
组件创建实例时,React 首先会调用 constructor
构造函数,然后调用 getDerivedStateFromProps
静态函数,返回 null
。接着,React 调用 render
函数,生成了组件的虚拟 DOM,并显示在页面上。最后,React 调用 componentDidMount
函数,此时组件已经被挂载到实际的 DOM 树上,可以进行一些初始化的操作。
快速掌握 React 基础入门: 一个完整的指南(三)https://developer.aliyun.com/article/1426134