React基本内容学习详细教程(3)
上篇续写
React基本内容学习详细教程(1)
React基本内容学习详细教程(2)
详细内容
1)React 组件生命周期
组件的生命周期可分成三个状态:
Mounting(挂载)
:已插入真实 DOMUpdating(更新)
:正在被重新渲染Unmounting(卸载)
:已移出真实 DOM
挂载
当组件实例被创建并插入 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()
:在组件卸载及销毁之前直接调用
。
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
// 初始化组件状态,包含一个名为date的属性,值为当前时间的Date对象
this.state = {
date: new Date() };
}
// 组件挂载完成后调用的生命周期方法
componentDidMount() {
// 使用定时器每秒更新一次组件状态中的date属性
this.timerID = setInterval(() => this.tick(), 1000);
}
// 组件卸载前调用的生命周期方法
componentWillUnmount() {
// 清除定时器
clearInterval(this.timerID);
}
// 更新组件状态的方法
tick() {
// 更新date属性为当前时间的Date对象
this.setState({
date: new Date()
});
}
render() {
return (
<div>
{
/* 显示标题 */}
<h1>Hello, react!</h1>
{
/* 显示当前时间 */}
<h2>现在时间是:{
this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
// 将Clock组件渲染到id为"example"的DOM元素中
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
Clock
的类组件。在构造函数中,初始化了组件的状态date
,值为当前时间的Date
对象。- 在
componentDidMount
生命周期方法中,使用定时器每秒更新一次组件状态的date属性
。 - 在
componentWillUnmount
生命周期方法中,清除定时器
,以防止在组件卸载后仍然执行更新。 tick
方法用于更新组件状态中的date属性为当前时间的Date对象
。- 在render方法中,通过
JSX
语法,将标题和显示当前时间的元素渲染到DOM中
。 {this.state.date.toLocaleTimeString()}
用于显示当前时间的格式化字符串。- 最后,通过
ReactDOM.render
将Clock
组件渲染到id为"example"的DOM
元素中。
2)React AJAX
React 组件
的数据可以通过 componentDidMount
方法中的 Ajax
来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI
。
当使用异步加载数据时,在组件卸载前使用componentWillUnmount
来取消未完成的请求。
3)React 表单与事件
- HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素生来就保留一些内部状态。
- 在 HTML 当中,像 , , 和 这类表单元素会维持自身状态,并根据用户输入进行更新。
但在React中,可变的状态通常保存在组件的状态属性中,并且只能用
setState() 方法进行更新
。import React from ‘react’;
import ReactDOM from ‘react-dom’;class Message extends React.Component {
constructor(props) {
super(props);
// 初始化组件状态
this.state = {
value: 'hello,world'
};
// 绑定change方法的上下文
this.change = this.change.bind(this);
}
// 当输入框的值发生变化时触发
change(event) {
// 更新组件状态,将输入框的值存储在state中
this.setState({
value: event.target.value });
}
render() {
// 从state中获取当前的值
var value = this.state.value;
return (
<div>
{
/* 输入框,value绑定为state中的值,onChange事件触发change方法 */}
<input type="text" value={
value} onChange={
this.change} />
{
/* 显示state中的值 */}
<h1>{
value}</h1>
</div>
);
}
}
ReactDOM.render(
<Message />,
document.getElementById('example')
);
如何在子组件上使用表单
。onChange
方法将触发state
的更新并将更新的值传递到子组件的输入框的 value 上来重新渲染界面
。你需要在
父组件
通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件
上。import React from ‘react’;
import ReactDOM from ‘react-dom’;// Content组件
class Content extends React.Component {render() {
return (
<div>
{
/* 输入框,value绑定为传入的myDataProp值,onChange事件绑定为传入的updateStateProp方法 */}
<input type="text" value={
this.props.myDataProp} onChange={
this.props.updateStateProp} />
{
/* 显示传入的myDataProp值 */}
<h4>{
this.props.myDataProp}</h4>
</div>
);
}
}
// HelloMessage组件
class HelloMessage extends React.Component {constructor(props) {
super(props);
// 初始化组件状态
this.state = {
value: '你好,Java!'
};
// 绑定handleChange方法的上下文
this.handleChange = this.handleChange.bind(this);
}
// 当输入框的值发生变化时触发
handleChange(event) {
// 更新组件状态,将输入框的值存储在state中
this.setState({
value: event.target.value });
}
render() {
var value = this.state.value;
return (
<div>
{
/* 渲染Content组件,传入value作为myDataProp,传入handleChange方法作为updateStateProp */}
<Content myDataProp={
value} updateStateProp={
this.handleChange} />
</div>
);
}
}
// 将HelloMessage组件渲染到id为”example”的DOM元素中
ReactDOM.render(<HelloMessage />,
document.getElementById('example')
);
代码中有两个组件:
Content
和HelloMessage
。- Content组件包含
一个输入框
和一个标题
,根据myDataProp
的值来设置输入框的值,并显示在标题中。 HelloMessage
组件包含一个状态value,初始化为"你好,Java!"
。它也有一个handleChange
方法,用于更新状态value的值
。- 在HelloMessage组件的
render
方法中,通过标签将Content组件渲染到DOM
中,传递了value
作为myDataProp
的值,并将handleChange
方法作为updateStateProp
传递给Content组件
。 - 最后,通过
ReactDOM.render
将HelloMessage
组件渲染到id
为"example"的DOM元素
中。
Select 下拉菜单
在 React 中,不使用 selected 属性,而在根 select 标签上用 value 属性来表示选中项。
多个表单
当你有处理多个 input
元素时,你可以通过给每个元素添加一个 name
属性,来让处理函数根据 event.target.name
的值来选择做什么
import React from 'react';
import ReactDOM from 'react-dom';
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) {
// 更新组件状态,将选择框的值存储在state中
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>
what website do you like?
<select value={
this.state.value} onChange={
this.handleChange}>
<option value="gg">Google</option>
<option value="rn">aaa</option>
<option value="tb">bbb</option>
<option value="fb">Facebook</option>
</select>
</label>
<input type="submit" value="提交" />
</form>
);
}
}
ReactDOM.render(
<FlavorForm />,
document.getElementById('example')
);
- 一个表单组件
FlavorForm
,其中包含一个选择框
和一个提交按钮
。 - 在组件的状态
value
中初始化为"coconut"
。 - 当
选择框
的值发生变化时,会触发handleChange
方法来更新组件的状态
。 当提交表单时
,会触发handleSubmit
方法来显示一个弹窗,展示选择的喜好。- 通过
ReactDOM.render
将FlavorForm
组件渲染到id
为"example"的DOM元素中
。
React 事件
通过 onClick 事件来修改数据
import React from 'react';
import ReactDOM from 'react-dom';
class HelloMessage extends React.Component {
constructor(props) {
super(props);
// 初始化组件状态
this.state = {
value: 'Hello react!'
};
// 绑定handleChange方法的上下文
this.handleChange = this.handleChange.bind(this);
}
// 处理按钮点击事件
handleChange(event) {
// 更新组件状态,将value值设置为'hello,world'
this.setState({
value: 'hello,world' });
}
render() {
var value = this.state.value;
return (
<div>
{
/* 按钮,点击时触发handleChange方法 */}
<button onClick={
this.handleChange}>点我</button>
{
/* 显示当前value的值 */}
<h4>{
value}</h4>
</div>
);
}
}
// 将HelloMessage组件渲染到id为"example"的DOM元素中
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
- 展示了一个按钮和一个标题。
初始时
,标题显示”Hello react!”。- 当按钮被点击时,会
触发handleChange方法
,该方法将组件状态中的value
值更新为"hello,world"
。 - 通过
ReactDOM.render
将HelloMessage
组件渲染到id
为"example"的DOM元素中
。
当你需要从子组件中更新父组件的 state 时,你需要在父组件通过创建事件句柄 (handleChange) ,并作为 prop (updateStateProp) 传递到你的子组件上。
import React from 'react';
import ReactDOM from 'react-dom';
class Content extends React.Component {
render() {
return (
<div>
{
/* 按钮,点击时触发传入的updateStateProp方法 */}
<button onClick={
this.props.updateStateProp}>点我</button>
{
/* 显示传入的myDataProp值 */}
<h4>{
this.props.myDataProp}</h4>
</div>
);
}
}
class HelloMessage extends React.Component {
constructor(props) {
super(props);
// 初始化组件状态
this.state = {
value: 'Hello react!'
};
// 绑定handleChange方法的上下文
this.handleChange = this.handleChange.bind(this);
}
// 处理按钮点击事件
handleChange(event) {
// 更新组件状态,将value值设置为'hello,world!'
this.setState({
value: 'hello,world!' });
}
render() {
var value = this.state.value;
return (
<div>
{
/* 渲染Content组件,传入value作为myDataProp,传入handleChange方法作为updateStateProp */}
<Content myDataProp={
value} updateStateProp={
this.handleChange} />
</div>
);
}
}
// 将HelloMessage组件渲染到id为"example"的DOM元素中
ReactDOM.render(
<HelloMessage />,
document.getElementById('example')
);
- 这段代码中有两个组件:
Content
和HelloMessage
。 - Content组件包含
一个按钮和一个标题
,根据myDataProp
的值来显示标题的内容。 - 按钮被点击时,
触发updateStateProp方法
。 HelloMessage
组件包含一个状态value
,初始化为”Hello react!”。- 它也有一个
handleChange
方法,用于更新状态value的值
。 - 在HelloMessage组件的
render
方法中,通过<Content>标签将Content组件渲染到DOM中,传递了value作为myDataProp的值
,并将handleChange方法作为updateStateProp
传递给Content
组件。 - 最后,通过
ReactDOM.render
将HelloMessage
组件渲染到id为”example”的DOM元素中。
4)React Refs
React 列表 & Keys
import React from 'react';
import ReactDOM from 'react-dom';
// 定义一个数组
const numbers = [1, 2, 3, 4, 5];
// 使用map方法遍历数组,生成一个包含li元素的数组
const listItems = numbers.map((number) =>
<li>{
number}</li>
);
// 将包含li元素的数组渲染为ul列表
ReactDOM.render(
<ul>{
listItems}</ul>,
document.getElementById('example')
);
这段代码将一个数组numbers
中的元素通过map方法遍历
,生成一个包含li
元素的新数组listItems
。
最后,通过ReactDOM.render
将listItems
渲染为一个无序列表(ul元素)并挂载到id为"example"的DOM
元素中。每个li元素的内容都是数组中对应的数字。
我们可以将以上实例重构成一个组件,组件接收数组参数,每个列表元素分配一个 key,不然会出现警告 a key should be provided for list items,意思就是需要包含 key:
import React from 'react';
import ReactDOM from 'react-dom';
// 定义一个函数组件NumberList
function NumberList(props) {
// 从props中获取传入的数组
const numbers = props.numbers;
// 使用map方法遍历数组,生成一个包含li元素的新数组
const listItems = numbers.map((number) =>
// 使用number作为key属性,确保每个元素在列表中具有唯一的标识
<li key={
number.toString()}>
{
number}
</li>
);
// 返回包含listItems的ul元素
return (
<ul>{
listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
// 渲染NumberList组件,并传入numbers作为props
ReactDOM.render(
<NumberList numbers={
numbers} />,
document.getElementById('example')
);
- 这段代码中定义了一个函数组件
NumberList
,它接受一个props
参数。 - 在函数组件中,我们从
props
中获取传入的数组numbers
。 - 然后,使用
map方法遍历数组
,并生成一个包含li
元素的新数组listItems
。 - 注意,在每个
li
元素上设置了一个唯一的key属性
,以确保每个元素在列表中具有唯一的标识
。 - 最后,函数组件返回一个包含
listItems的ul元素
。 - 通过
ReactDOM.render
将NumberList
组件渲染到id为”example”的DOM元素中,同时将numbers
作为numbers
属性传递给组件。这样,列表中的每个数字将被渲染为一个li元素。
Keys
Keys 可以在 DOM 中的某些元素被增加或删除
的时候帮助 React 识别哪些元素发生了变化。
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={
number.toString()}>
{
number}
</li>
);
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的 id 作为元素的 key:
const todoItems = todos.map((todo) =>
<li key={
todo.id}>
{
todo.text}
</li>
);
当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key:
const todoItems = todos.map((todo, index) =>
// 只有在没有确定的 id 时使用
<li key={
index}>
{
todo.text}
</li>
);
如果列表可以重新排序,我们不建议使用索引来进行排序,因为这会导致渲染变得很慢。
还没有评论,来说两句吧...