7.6 已OFFER
1. 组件封装思路
封装组件的主要目标是提高代码复用性、易维护性和可测试性。以下是一些封装组件的思路:
高内聚,低耦合:组件的内部实现应当与外部使用尽量解耦,减少组件的依赖性,使组件更易于重用和维护。
单一职责:每个组件应该只负责一项任务,如展示一个 UI 元素、处理特定的逻辑等。避免组件职责过于复杂。
可配置性:通过
props
传递参数,使组件具备一定的灵活性和可配置性。组件内部应支持合理的默认值和必要的验证。状态管理:根据需要合理管理组件的内部状态,确定哪些状态需要提升至父组件或使用全局状态管理工具(如 Redux)。
使用 Hooks:React Hooks(如
useState
、useEffect
等)可以帮助简化逻辑,避免复杂的生命周期管理。分离样式和逻辑:通过 CSS-in-JS 或 styled-components,将样式与逻辑分离,使代码更加清晰。
组合模式:使用组合模式代替继承,通过组合多个简单组件来构建复杂组件。
2. 父子组件交互实例
父子组件之间的交互可以通过 props
和回调函数实现。
父组件:
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [message, setMessage] = useState('Hello from Parent');
const handleMessageChange = (newMessage) => {
setMessage(newMessage);
};
return (
<div>
<h1>Parent Component</h1>
<ChildComponent message={message} onMessageChange={handleMessageChange} />
</div>
);
}
export default ParentComponent;
子组件:
import React from 'react';
function ChildComponent({ message, onMessageChange }) {
const updateMessage = () => {
onMessageChange('Hello from Child');
};
return (
<div>
<h2>Child Component</h2>
<p>{message}</p>
<button onClick={updateMessage}>Update Message</button>
</div>
);
}
export default ChildComponent;
在这个例子中,ParentComponent
通过 props
将状态 message
和修改状态的函数 onMessageChange
传递给 ChildComponent
。子组件通过调用 onMessageChange
修改父组件的状态。
3. 数组解构
数组解构允许从数组中提取值,并将其赋值给变量。
示例:
const [a, b, c] = [1, 2, 3];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
// 也可以跳过一些元素
const [first, , third] = [10, 20, 30];
console.log(first); // 10
console.log(third); // 30
4. 父组件调用子组件方法
为了让父组件调用子组件中的方法,可以使用 React.forwardRef
和 useImperativeHandle
。
示例:
子组件:
import React, { forwardRef, useImperativeHandle } from 'react';
const ChildComponent = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
childMethod() {
console.log('Child method called');
}
}));
return <div>Child Component</div>;
});
export default ChildComponent;
父组件:
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const childRef = useRef();
const callChildMethod = () => {
if (childRef.current) {
childRef.current.childMethod();
}
};
return (
<div>
<h1>Parent Component</h1>
<ChildComponent ref={childRef} />
<button onClick={callChildMethod}>Call Child Method</button>
</div>
);
}
export default ParentComponent;
5. React Hooks 示例
- useState:管理组件内部的状态。
const [count, setCount] = useState(0);
- useEffect:管理副作用,如数据获取、订阅、DOM 操作等。
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
- useRef:引用 DOM 元素或保持跨渲染周期的值。
const inputRef = useRef(null);
- useContext:共享组件树中的数据。
const value = useContext(MyContext);
6. useState 和 useRef 的区别
useState:用于声明组件的状态变量,更新状态会触发组件重新渲染。
useRef:用于创建一个保持跨渲染周期的可变引用,改变
useRef
的值不会触发组件重新渲染。
7. 改变数组或对象以触发重新渲染
当 useState
中存储的是数组或对象时,不能直接修改原始数据结构,否则不会触发重新渲染。需要创建新数组或对象来进行更新。
// 错误方式:直接修改不会触发渲染
const [state, setState] = useState({ name: 'John', age: 30 });
state.name = 'Jane';
setState(state); // 不会触发渲染
// 正确方式:创建新对象
setState({ ...state, name: 'Jane' }); // 会触发渲染
8. useState 定义对象状态的示例
const [user, setUser] = useState({ name: 'John', age: 30 });
const updateUserName = () => {
setUser({ ...user, name: 'Jane' });
};
9. React 状态管理机制和渲染优化策略
React 的状态管理机制主要通过 useState
、useReducer
和全局状态管理库(如 Redux)来管理组件的状态。每当状态更新时,React 会重新渲染受影响的组件或子树。
React 的渲染优化策略包括:
虚拟 DOM:React 在内存中维护一个虚拟 DOM,更新时将新旧虚拟 DOM 进行比较(Diff),并最小化实际 DOM 操作。
shouldComponentUpdate 和 React.memo:通过控制组件的更新逻辑,避免不必要的渲染。
React.lazy 和 Suspense:实现按需加载组件,减少初始渲染的负担。
10. 从 JS 底层数据类型在内存中的特性来解释对象或数组的更新
在 JavaScript 中,对象和数组是引用类型,变量存储的是对象或数组的内存地址,而不是值本身。直接修改对象或数组的属性值并不会改变其引用地址,React 无法检测到引用地址的变化,因此不会触发重新渲染。
11. 浏览器访问服务器的链路和过程
当你在浏览器输入服务器的 IP 和端口访问网站时,经历的过程包括:
DNS 解析:将域名解析为服务器的 IP 地址。
TCP 连接:客户端通过三次握手与服务器建立 TCP 连接。
发送 HTTP 请求:客户端通过 TCP 连接发送 HTTP 请求到服务器。
服务器处理请求:服务器处理请求,生成响应内容。
返回 HTTP 响应:服务器将响应数据通过 TCP 连接发送回客户端。
浏览器渲染页面:浏览器解析响应的 HTML、CSS 和 JavaScript,生成并渲染页面。
资源加载:浏览器解析 HTML 文件时,可能会遇到 CSS、JS、图片等资源链接,浏览器会发起新的 HTTP 请求来获取这些资源,并继续渲染页面。