转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
涉及面试题:
1. React 的状态是什么?
2. React 中的 props 是什么?
3. 状态和属性有什么区别?
4. 为什么不能直接更新状态?
5. 回调函数作为 setState() 参数的目的是什么?
6. 如果在构造函数中使用 setState() 会发生什么?
7. 构造函数使用带 props 参数的目的是什么?
8. 什么是调解?
9. 如何使用动态属性名设置 state?
10. 在 React 中如何校验 props 属性?
11. 如果在初始状态中使用 props 属性会发生什么?
12. 为什么在 DOM 元素上展开 props 需要小心?
13. 为什么需要将函数传递给 setState() 方法?
14. 如何在 attribute 引号中访问 props 属性?
15. setState() 和 replaceState() 方法之间有什么区别?
16. 更新状态中的对象有哪些可能的方法?
17. 为什么函数比对象更适合于 setState()?
18. 如何使用 setState 防止不必要的更新?
19. 什么时候组件的 props 属性默认为 true?
编号:[react_12]
1 state 与 render 函数的关系
通过之前文章的学习,我们可以很明显地感受到,React 是一门由“数据”驱动的框架——当数据发生变化,页面就会自动地跟着发生变化。
❓这背后的原理是怎样的呢?
答:(先给出结论,再详细讲解)当组件的 state
或者 props
发生改变的时候, render
函数就会重新执行。而页面又是 render
函数渲染出来的,故数据发生变化,页面就会自动地跟着发生变化!
紧接上一篇的代码,我们打开 TodoList.js
文件。
1️⃣先演示 state
发生变化,页面跟着变化的情形:
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";
import "./style.css";
class TodoList extends Component {
constructor(props) {
super(props);
this.state = { /*
1️⃣-①:一旦 state 发生改变(我们可以在页面的 input 框输入任意内容,
来使 state 发生改变),
*/
inputValue: "",
list: []
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBtnClick = this.handleBtnClick.bind(this);
this.handleItemDelete = this.handleItemDelete.bind(this);
}
render() { // 1️⃣-②:render 函数就会重新执行(即,重新用新的数据渲染页面)。
console.log("render") /*
1️⃣-③:为了演示 render 函数确实执行了,
我们让控制台给我们实时打印一些信息。
*/
return(
<Fragment>
<div>
<label htmlFor="insertArea">请输入要进行的事项:</label>
<input
id="insertArea"
className="input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<button onClick={this.handleBtnClick}>
提交
</button>
</div>
<ul>
{this.getTodoItem()}
</ul>
</Fragment>
)
}
getTodoItem() {
return this.state.list.map((item, index) => {
return(
<TodoItem
key={index}
content={item}
index={index}
itemDelete={this.handleItemDelete}
/>
)
})
}
handleInputChange(e) {
const value = e.target.value
this.setState(() => ({
inputValue: value
}))
}
handleBtnClick() {
this.setState((prevState) => ({
list: [...prevState.list, prevState.inputValue],
inputValue: ""
}))
}
handleItemDelete(index) {
this.setState((prevState) => {
const list = [...prevState.list]
list.splice(index, 1)
return {list}
})
}
}
export default TodoList;
看下页面效果(我们在 input 框的每次输入都改变了 state,所以 render 函数也相应地在执行):
2 props 与 render 函数的关系
2️⃣打开 TodoItem.js
文件,我们继续演示 props
发生变化,页面跟着变化的情形:
import React, { Component } from "react";
import PropTypes from "prop-types";
class TodoItem extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
console.log("TodoItem render") /*
2️⃣-③:在页面 input 框输入内容并点击“提交”后,
子组件的 render 函数都会相应执行。
❗️❗️❗️其原因有二:
第一,子组件的 content 是从父组件接收的,在父组件 TodoList 里,
content 的值是“列表循环出的每一项”。故,当我们输入内容并提交后,
“列表循环出的每一项”会随之变化,继而子组件接收到的属性也会变化,
子组件的 render 函数相应地会根据新的值进行重新渲染;
第二,当父组件的 render 函数被运行时,它的子组件的 render 函数
都将被运行一次!
因为,子组件 TodoItem 是被父组件 TodoList 的 render 渲染出来的,
那么,父组件的 render 在被重新执行时,子组件的 render 也会被执行。
*/
const {content, test} = this.props /*
2️⃣-①:this.props 是父组件
通过“属性”传递过来的内容;
*/
return(
<div onClick={this.handleClick}>
{test}{content} {/* 2️⃣-②:我们将内容项 content 展示在页面; */}
</div>
)
}
handleClick() {
const {itemDelete, index} = this.props
itemDelete(index)
}
}
TodoItem.propTypes = {
test: PropTypes.string.isRequired,
content: PropTypes.string,
itemDelete: PropTypes.func,
index: PropTypes.number
}
TodoItem.defaultProps = {
test: "hello, "
}
export default TodoItem;
看看页面效果,结合本篇所讲和之前实现代码时的逻辑,尝试对控制台打印出的每一行内容作分析(思路很清晰了对不对~):
有了本篇的基础,我们就可以比较轻松地去学习“虚拟 DOM”的知识了。待“虚拟 DOM”的三篇文章学完,再回来看本篇文章时,你将会对 React 的“数据驱动”思想有更深的理解!
祝好,qdywxs ♥ you!