答案解析:
React 是一个用于构建用户界面的 JavaScript 库,主要用于构建单页应用。其主要特点包括:
答案解析:
React 组件有几个生命周期阶段,主要包括:
constructor
、componentDidMount
。componentDidUpdate
、shouldComponentUpdate
。componentWillUnmount
。每个生命周期方法提供了在特定时间点执行代码的机会,允许开发者控制组件的行为。
答案解析:
答案解析:
React Hooks 是 React 16.8 中引入的新特性,允许在函数组件中使用状态和生命周期特性。常用的 Hooks 包括:
useState
:用于在函数组件中添加状态。useEffect
:用于处理副作用(如数据获取、订阅等)。useContext
:用于访问 React 上下文。Hooks 提供了一种更优雅的方式来管理组件状态和副作用,避免了类组件的复杂性。
答案解析:
高阶组件是一个函数,它接受一个组件并返回一个新组件。HOC 用于复用组件逻辑,常用于:
例如,withRouter
是一个高阶组件,用于向组件提供路由相关的 props。
答案解析:
React 上下文提供了一种在组件树中共享数据的方式,而不必通过每一个组件的 props 手动传递。上下文适用于:
使用 React.createContext()
创建上下文,并通过 Provider
组件提供数据,通过 Consumer
组件或 useContext
Hook 访问数据。
答案解析:
在 React 中,事件处理与原生 JavaScript 略有不同:
onClick
。this
,可使用箭头函数或在构造函数中绑定。class MyComponent extends React.Component {
handleClick = () => {
console.log('Clicked!');
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
答案解析:
React Router 是一个用于处理 React 应用路由的库,允许在单页应用中实现多页面导航。基本用法如下:
BrowserRouter
包裹应用的根组件。Route
和 Link
组件定义路由和导航。import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
答案解析:
条件渲染是根据某些条件动态决定渲染哪些组件或元素。在 React 中,可以使用 JavaScript 的条件语句(如 if
、三元运算符等)进行条件渲染。例如:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? <LogoutButton /> : <LoginButton />}
</div>
);
}
答案解析:
优化 React 应用性能的方法包括:
React.memo
对组件进行性能优化,防止不必要的渲染。useMemo
和 useCallback
缓存计算结果和函数引用。React.lazy
和 Suspense
按需加载组件。shouldComponentUpdate
返回正确的值。答案解析:
React 的 Fragment 是一个无形的容器,用于将多个子元素组合在一起,而不在 DOM 中添加额外的节点。它主要用于避免不必要的 div 嵌套。使用方式如下:
import React from 'react';
function MyComponent() {
return (
<React.Fragment>
<h1>Title</h1>
<p>Description</p>
</React.Fragment>
);
}
// 或者使用简写
function MyComponent() {
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
}
答案解析:
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
return <input type="text" value={this.state.value} onChange={this.handleChange} />;
}
}
ref
来访问其值。例如:class MyForm extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
handleSubmit = (event) => {
event.preventDefault();
alert('A name was submitted: ' + this.inputRef.current.value);
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={this.inputRef} />
<button type="submit">Submit</button>
</form>
);
}
}
答案解析:
错误边界是 React 16 引入的特性,用于捕获子组件树中的 JavaScript 错误,防止整个组件树崩溃。错误边界是实现了 componentDidCatch
和 getDerivedStateFromError
生命周期方法的类组件。例如:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
useReducer
Hook?答案解析:
useReducer
是一个 Hook,用于在函数组件中管理复杂的状态。它接收一个 reducer 函数和初始状态,返回当前状态和 dispatch 函数。适合用于管理多个子状态或复杂状态逻辑的场景。
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
答案解析:
组件的懒加载可以使用 React.lazy
和 Suspense
来实现。React.lazy
用于动态导入组件,Suspense
用于提供加载状态。示例:
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
useEffect
Hook。答案解析:
useEffect
是一个用于处理副作用的 Hook,类似于类组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
。它在组件渲染后执行,可以用来进行数据获取、订阅设置等操作。
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 组件挂载时执行的代码
const timer = setTimeout(() => {
console.log('Hello, World!');
}, 1000);
// 清理函数
return () => clearTimeout(timer);
}, []); // 依赖数组,空数组表示只在挂载和卸载时执行
return <div>My Component</div>;
}
答案解析:
表单验证可以通过状态管理和条件渲染来实现。可以在输入框的 onChange
事件中进行验证,然后根据验证结果更新状态,显示错误消息。
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '', error: '' };
}
handleChange = (event) => {
const value = event.target.value;
this.setState({ value });
if (value.length < 3) {
this.setState({ error: 'Input must be at least 3 characters long.' });
} else {
this.setState({ error: '' });
}
};
render() {
return (
<div>
<input type="text" value={this.state.value} onChange={this.handleChange} />
{this.state.error && <span style={{ color: 'red' }}>{this.state.error}</span>}
</div>
);
}
}
key
属性有什么作用?答案解析:
key
属性用于标识组件在列表中的唯一性,帮助 React 确定哪些项改变、添加或删除。使用 key
可以提高渲染性能,避免不必要的重新渲染。key
应该是稳定且唯一的标识符,通常使用数据库中的 ID。
const items = ['apple', 'banana', 'orange'];
function ItemList() {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
useMemo
和 useCallback
Hook?答案解析:
useMemo
:用于缓存计算结果,避免在每次渲染时重新计算,适合用于性能优化。例如:const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
:用于缓存函数引用,避免在每次渲染时重新创建函数,适合用于性能优化。例如:const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
答案解析:
Server-Side Rendering (SSR) 是指在服务器上渲染 React 组件,并将生成的 HTML 发送到客户端。这种方式可以提高页面加载速度,优化 SEO,因为搜索引擎可以直接抓取服务器返回的 HTML 内容。常用的 SSR 框架包括 Next.js。
使用 SSR 时,应用可以在服务器端执行 React 组件,生成完整的 HTML 页面,客户端接收这些页面并进行交互。
答案解析:
React 的合成事件系统是一个跨浏览器的事件处理机制,旨在提供一致的事件行为。其主要特点包括:
event.target
)在事件处理后会被重置。若需要保留事件对象,可以使用 event.persist()
。使用合成事件时,事件名称使用小写字母,例如 onClick
,并且事件处理函数作为属性传递。
function MyButton() {
const handleClick = (event) => {
event.persist(); // 允许使用事件对象
console.log(event.target);
};
return <button onClick={handleClick}>Click Me</button>;
}
答案解析:
在 React 中,可以通过内联样式或 CSS 类来实现动态样式。
function MyComponent({ isActive }) {
const style = {
backgroundColor: isActive ? 'green' : 'red',
color: 'white',
padding: '10px',
};
return <div style={style}>Dynamic Style Box</div>;
}
classnames
)动态应用 CSS 类。import classNames from 'classnames';
function MyComponent({ isActive }) {
const className = classNames({
active: isActive,
inactive: !isActive,
});
return <div className={className}>Dynamic Class Box</div>;
}
答案解析:
Context API 提供了一种在组件树中共享状态的方式,而不必通过每一个组件的 props 手动传递。它主要由 createContext
、Provider
和 Consumer
组成。
const MyContext = React.createContext();
function App() {
return (
<MyContext.Provider value={{ name: 'John' }}>
<MyComponent />
</MyContext.Provider>
);
}
Context.Consumer
或 useContext
Hook 获取。function MyComponent() {
return (
<MyContext.Consumer>
{value => <div>{value.name}</div>}
</MyContext.Consumer>
);
}
// 使用 useContext Hook
import { useContext } from 'react';
function MyComponent() {
const value = useContext(MyContext);
return <div>{value.name}</div>;
}
useRef
Hook。答案解析:
useRef
是一个 Hook,用于创建一个可变的引用对象,该对象的 .current
属性可以持久化存储值。useRef
的常见用法包括:
ref
属性将 useRef
创建的引用对象附加到一个元素上,以便直接访问该元素。import React, { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
useRef
也可以用于保持组件的状态而不引起重新渲染。function Timer() {
const countRef = useRef(0);
const increment = () => {
countRef.current += 1;
console.log(countRef.current);
};
return <button onClick={increment}>Increment</button>;
}
useLayoutEffect
Hook。答案解析:
useLayoutEffect
是一个 Hook,与 useEffect
类似,但它在 DOM 更新后、浏览器绘制之前同步执行。这意味着它可以用于读取布局并同步触发重渲染。常见用途包括:
import React, { useLayoutEffect, useRef } from 'react';
function MyComponent() {
const divRef = useRef(null);
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
console.log(rect);
}, []);
return <div ref={divRef}>Measure Me!</div>;
}
答案解析:
Portal 是 React 16 引入的特性,允许将子组件渲染到 DOM 树中的不同位置。它常用于模态框、工具提示等需要脱离父组件层级结构的场景。
使用 ReactDOM.createPortal
创建 Portal,如下所示:
import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal">{children}</div>,
document.getElementById('modal-root') // 指定渲染目标
);
}
// 使用 Modal
function App() {
return (
<div>
<h1>My App</h1>
<Modal>My Modal Content</Modal>
</div>
);
}
答案解析:
处理 React 应用中的状态管理可以通过多种方式实现,常见的方法包括:
useState
和 useReducer
管理组件的本地状态。例如,使用 Redux 进行状态管理:
import { createStore } from 'redux';
import { Provider } from 'react-redux';
// Reducer
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
};
// 创建 Redux store
const store = createStore(reducer);
// 使用 Provider 包裹应用
function App() {
return (
<Provider store={store}>
<MyComponent />
</Provider>
);
}
StrictMode
?答案解析:
StrictMode
是一个用于帮助识别潜在问题的工具,主要用于开发模式下。它不会渲染任何 UI,而是通过检测不安全的生命周期、过时的 API 使用等方式来帮助开发者发现问题。
使用 StrictMode
包裹应用的示例:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <h1>Hello, World!</h1>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
答案解析:
在 React 中,可以使用内置的 fetch
API 或第三方库(如 Axios)处理 API 请求。通常在 useEffect
中发起请求,以便在组件挂载时获取数据。
使用 fetch
的示例:
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data))
.catch(error => console.error('Error fetching data:', error));
}, []); // 空依赖数组表示只在挂载时执行
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
memo
和 forwardRef
。答案解析:
memo
:用于优化组件性能,避免不必要的重新渲染。它会对比前后 props,如果没有变化,则不会重新渲染组件。const MyComponent = React.memo(({ name }) => {
console.log('Rendering:', name);
return <div>Hello, {name}</div>;
});
forwardRef
:用于转发 refs 到子组件,允许父组件访问子组件的 DOM 元素或类实例。const MyInput = React.forwardRef((props, ref) => {
return <input ref={ref} {...props} />;
});
// 使用 MyInput
function ParentComponent() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<MyInput ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
答案解析:
高阶组件(Higher-Order Component,HOC)是一个函数,它接收一个组件并返回一个新的组件。HOC 用于复用组件逻辑和增强功能。常见用途包括:
示例:
import React from 'react';
// 高阶组件
const withLoading = (WrappedComponent) => {
return class extends React.Component {
render() {
const { isLoading, ...otherProps } = this.props;
return isLoading ? <div>Loading...</div> : <WrappedComponent {...otherProps} />;
}
};
};
// 使用高阶组件
const MyComponent = (props) => <div>{props.data}</div>;
const MyComponentWithLoading = withLoading(MyComponent);
// 使用示例
function App() {
return <MyComponentWithLoading isLoading={true} data="Hello, World!" />;
}
useImperativeHandle
Hook。答案解析:
useImperativeHandle
是一个 Hook,允许将函数组件的实例值暴露给父组件。常与 forwardRef
一起使用,可以自定义父组件访问子组件的实例值。它使得父组件能够使用子组件的特定功能,而不需要直接访问子组件的实现细节。
示例:
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
// 子组件
const MyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} />;
});
// 父组件
function ParentComponent() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus();
};
return (
<>
<MyInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
</>
);
}
答案解析:
在 React 中,可以通过管理组件状态来实现表单的重置功能。可以维护一个状态来存储表单字段的值,并在需要重置时将状态重置为初始值。
示例:
import React, { useState } from 'react';
function MyForm() {
const [formData, setFormData] = useState({ name: '', email: '' });
const handleChange = (event) => {
const { name, value } = event.target;
setFormData({ ...formData, [name]: value });
};
const handleReset = () => {
setFormData({ name: '', email: '' }); // 重置为初始值
};
return (
<form>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
<button type="button" onClick={handleReset}>Reset</button>
</form>
);
}
useContext
Hook。答案解析:
useContext
是一个 Hook,允许函数组件访问 React 上下文。通过传递上下文对象作为参数,useContext
返回当前上下文的值。它使得在组件树中访问上下文变得更加简洁。
示例:
import React, { createContext, useContext } from 'react';
// 创建上下文
const ThemeContext = createContext('light');
function ThemedComponent() {
const theme = useContext(ThemeContext); // 访问上下文值
return <div style={{ background: theme === 'dark' ? '#333' : '#fff' }}>Themed Component</div>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedComponent />
</ThemeContext.Provider>
);
}
useCallback
和它的作用。答案解析:
useCallback
是一个 Hook,用于缓存函数的引用,避免在组件重新渲染时创建新的函数实例。它的主要作用是优化性能,特别是在将回调函数传递给子组件时,防止不必要的重新渲染。
示例:
import React, { useState, useCallback } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
// 使用 useCallback 缓存 increment 函数
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // 依赖数组为空,函数只会在第一次渲染时创建
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
答案解析:
在 React 中,可以通过错误边界(Error Boundaries)捕获子组件树中的 JavaScript 错误,以防止整个应用崩溃。错误边界是实现了 componentDidCatch
和 getDerivedStateFromError
方法的类组件。
示例:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true }; // 更新状态以显示备用 UI
}
componentDidCatch(error, info) {
console.error('Error occurred:', error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children; // 正常渲染子组件
}
}
// 使用 ErrorBoundary
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
useMemo
Hook,如何使用它?答案解析:
useMemo
是一个 Hook,用于缓存计算结果,避免在每次渲染时重新计算。它接受一个计算函数和依赖数组,当依赖项发生改变时,useMemo
才会重新计算。
示例:
import React, { useMemo } from 'react';
function MyComponent({ items }) {
// 使用 useMemo 缓存计算结果
const total = useMemo(() => {
return items.reduce((sum, item) => sum + item, 0);
}, [items]); // 依赖数组,只有 items 变化时才重新计算
return <div>Total: {total}</div>;
}
答案解析:
React Router 是一个流行的库,用于在 React 应用中实现路由。可以使用 BrowserRouter
、Route
和 Link
来定义路由和导航。
示例:
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
StrictMode
,以及它的作用。答案解析:
StrictMode
是一个用于识别潜在问题的工具,主要用于开发模式。它不会渲染任何 UI,而是帮助开发者发现不安全的生命周期、过时的 API 使用等。
用途:
示例:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <h1>Hello, World!</h1>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
答案解析:
在 React 中,可以使用 async/await
、Promise
或者第三方库(如 Axios)来处理异步操作。通常在 useEffect
中发起异步请求,以便在组件挂载时获取数据。
示例:
import React, { useEffect, useState } from 'react';
function MyComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []); // 空依赖数组表示只在挂载时执行
if (loading) {
return <div>Loading...</div>;
}
return <div>{JSON.stringify(data)}</div>;
}
useEffect
的清理函数。答案解析:
useEffect
可以返回一个清理函数,用于清理副作用,比如取消订阅、清除定时器等。这个清理函数在组件卸载时或在依赖项更新时执行。
示例:
import React, { useEffect, useState } from 'react';
function TimerComponent() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setSeconds((prev) => prev + 1);
}, 1000);
// 清理函数
return () => {
clearInterval(timer); // 组件卸载时清除定时器
};
}, []); // 依赖数组为空,表示只在组件挂载时执行
return <div>Seconds: {seconds}</div>;
}
答案解析:
组件间通信可以通过多种方式实现:
function Parent() {
const [message, setMessage] = useState('Hello from Parent');
return <Child message={message} />;
}
function Child({ message }) {
return <div>{message}</div>;
}
const MyContext = createContext();
function Parent() {
const value = 'Hello from Context';
return (
<MyContext.Provider value={value}>
<Child />
</MyContext.Provider>
);
}
function Child() {
const message = useContext(MyContext);
return <div>{message}</div>;
}
答案解析:
onChange
事件更新。function ControlledForm() {
const [value, setValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
};
return <input type="text" value={value} onChange={handleChange} />;
}
ref
直接访问 DOM 元素,React 不管理其状态。function UncontrolledForm() {
const inputRef = useRef();
const handleSubmit = () => {
alert('Input value: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
答案解析:
function MyFunctionComponent() {
return <div>Hello, Function Component!</div>;
}
React.Component
。需要实现 render
方法,可以使用生命周期方法。class MyClassComponent extends React.Component {
render() {
return <div>Hello, Class Component!</div>;
}
}
函数组件通常是首选,因为它们更轻量且易于理解,尤其是在使用 Hooks 时。
key
属性,为什么重要?答案解析:
key
属性是用于标识列表中每个元素的唯一标识符。它在 React 进行渲染时,帮助识别哪些元素发生了变化、添加或删除。使用唯一的 key
可以提高性能,避免不必要的重新渲染。
示例:
const items = ['apple', 'banana', 'orange'];
function ItemList() {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li> // 使用 index 作为 key,尽量使用唯一标识符
))}
</ul>
);
}
注意:在列表项的位置可能变化时,避免使用数组的索引作为 key
,因为这可能导致性能问题和状态问题。
forwardRef
和它的用途。答案解析:
forwardRef
是一个高阶组件,允许将 refs 转发到子组件,从而使父组件能够直接访问子组件的 DOM 元素或实例。它用于处理需要访问子组件内部元素的场景。
示例:
const FancyInput = React.forwardRef((props, ref) => (
<input ref={ref} type="text" className="fancy-input" />
));
function Parent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // 直接访问子组件的输入框
};
return (
<>
<FancyInput ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
useReducer
Hook 的使用场景。答案解析:
useReducer
是一个 Hook,用于管理复杂的状态逻辑,尤其是在状态依赖于先前状态的情况下。它类似于 Redux 中的 reducer,适合于涉及多个子值的状态或状态逻辑复杂的场景。
示例:
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
答案解析:
优化 React 应用的性能可以通过以下方法实现:
const MyComponent = React.memo(({ data }) => {
return <div>{data}</div>;
});
使用 useCallback
和 useMemo
:缓存函数和计算结果,减少渲染次数。
避免不必要的状态更新:确保只在需要时更新状态,使用 shouldComponentUpdate
或 React.PureComponent
。
代码分割:使用 React.lazy
和 Suspense
实现懒加载,提高初始加载速度。
使用虚拟化列表:对于长列表,使用库如 react-window
或 react-virtualized
进行列表虚拟化。
答案解析:
Portals 是 React 16 引入的特性,允许将子组件渲染到 DOM 树中的不同位置,而不是其父组件的 DOM 层级中。常用于模态框、工具提示等需要独立于父组件的场景。
示例:
import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal">{children}</div>,
document.getElementById('modal-root') // 渲染到指定的 DOM 节点
);
}
function App() {
return (
<>
<h1>My App</h1>
<Modal>
<h2>My Modal</h2>
</Modal>
</>
);
}
答案解析:
在 React 中处理 CSS 可以通过多种方式实现:
const style = { color: 'red', fontSize: '20px' };
function MyComponent() {
return <div style={style}>Hello, World!</div>;
}
/* styles.module.css */
.myComponent {
color: blue;
}
import styles from './styles.module.css';
function MyComponent() {
return <div className={styles.myComponent}>Hello, World!</div>;
}
import styled from 'styled-components';
const MyDiv = styled.div`
color: green;
font-size: 24px;
`;
function MyComponent() {
return <MyDiv>Hello, World!</MyDiv>;
}
shouldComponentUpdate
方法及其用途。答案解析:
shouldComponentUpdate
是类组件中的生命周期方法,允许开发者控制组件是否重新渲染。它接收下一个 props 和状态作为参数,并返回一个布尔值。如果返回 false
,组件将跳过渲染过程。
用途:
示例:
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// 只在某些条件下进行更新
return nextProps.value !== this.props.value;
}
render() {
return <div>{this.props.value}</div>;
}
}
答案解析:
Fragment 是 React 提供的一个组件,用于将多个子元素组合在一起,而不在 DOM 中添加额外的节点。它可以避免多余的 div 元素,有助于提高代码的可读性和结构。
用法:
或简写 <>
来定义片段。示例:
function MyComponent() {
return (
<React.Fragment>
<h1>Title</h1>
<p>Description</p>
</React.Fragment>
);
}
// 或者使用简写
function MyComponent() {
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
}
答案解析:
在 React 中处理多种输入类型的表单,可以通过将输入值存储在状态中,并在 onChange
事件中处理每种输入类型的变化。可以使用 name
属性来动态更新状态。
示例:
import React, { useState } from 'react';
function MyForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
age: '',
});
const handleChange = (event) => {
const { name, value } = event.target;
setFormData({ ...formData, [name]: value });
};
return (
<form>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
<input
type="number"
name="age"
value={formData.age}
onChange={handleChange}
placeholder="Age"
/>
</form>
);
}
useDebugValue
Hook。答案解析:
useDebugValue
是一个自定义 Hook 用于在 React 开发工具中显示调试信息。它允许开发者为自定义 Hook 提供更清晰的调试信息,帮助开发者在使用时更容易理解状态。
示例:
import { useState, useDebugValue } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// 使用 useDebugValue 提供调试信息
useDebugValue(isOnline ? 'Online' : 'Offline');
// ...其他逻辑
return isOnline;
}
答案解析:
懒加载是一种优化技术,可以在需要时加载组件或资源,而不是在应用启动时加载所有内容。React 提供了 React.lazy
和 Suspense
来实现组件的懒加载。
示例:
import React, { Suspense, lazy } from 'react';
// 使用 React.lazy 动态导入组件
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
useMemo
和 useCallback
的区别。答案解析:
useMemo
:用于缓存计算结果,避免在每次渲染时重新计算。它接受一个计算函数和依赖数组,仅在依赖项变化时重新计算。const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
:用于缓存函数的引用,避免在每次渲染时重新创建函数。它接受一个函数和依赖数组,仅在依赖项变化时更新函数引用。const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
答案解析:
处理异步事件可以使用 async/await
、Promise
或者通过 useEffect
来管理副作用。通常在处理 API 请求或需要等待的操作时使用。
示例:
import React, { useState, useEffect } from 'react';
function AsyncComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setLoading(false);
}
};
fetchData();
}, []); // 依赖数组为空,表示只在挂载时执行
if (loading) {
return <div>Loading...</div>;
}
return <div>{JSON.stringify(data)}</div>;
}
componentDidCatch
方法。答案解析:
componentDidCatch
是类组件的生命周期方法,用于捕获子组件树中的 JavaScript 错误,并可以记录错误信息或显示备用 UI。它与错误边界一起使用。
示例:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true }; // 更新状态以显示备用 UI
}
componentDidCatch(error, info) {
console.error('Error caught in Error Boundary:', error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children; // 正常渲染子组件
}
}
// 使用 ErrorBoundary
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
答案解析:
在 React 中处理 CSS 动画可以通过多种方式实现:
.fade-in {
animation: fadeIn 1s;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
function MyComponent() {
return <div className="fade-in">Hello, World!</div>;
}
react-spring
或 framer-motion
,提供更强大的动画控制。使用 framer-motion
的示例:
import { motion } from 'framer-motion';
function MyComponent() {
return (
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 1 }}>
Hello, World!
</motion.div>
);
}
答案解析:
React Router 允许使用参数化路由来传递动态数据。可以在路由路径中定义参数,并通过 useParams
Hook 获取这些参数。
示例:
import React from 'react';
import { BrowserRouter as Router, Route, Link, useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return <h2>User ID: {id}</h2>;
}
function App() {
return (
<Router>
<nav>
<Link to="/user/1">User 1</Link>
<Link to="/user/2">User 2</Link>
</nav>
<Route path="/user/:id" component={User} />
</Router>
);
}
答案解析:
在 React 中使用 TypeScript 可以提供类型安全,改善开发体验。要在 React 项目中使用 TypeScript,通常需要创建一个 TypeScript 配置文件并为组件定义类型。
步骤:
创建 TypeScript 项目:可以使用 create-react-app
直接创建 TypeScript 项目。
npx create-react-app my-app --template typescript
定义组件的 props 类型:
import React from 'react';
interface GreetingProps {
name: string;
}
const Greeting: React.FC = ({ name }) => {
return Hello, {name}!
;
};
export default Greeting;
import React from 'react';
import Greeting from './Greeting';
const App: React.FC = () => {
return ;
};
export default App;
TypeScript 还可以用于管理状态、上下文等,确保类型安全。
useTransition
和 startTransition
。答案解析:
useTransition
是 React 18 引入的 Hook,用于在渲染过程中标记某些状态更新为非紧急状态,允许 React 优先处理更紧急的更新。它帮助开发者实现更流畅的用户体验。
用法:
useTransition
来创建一个状态和一个布尔值,指示是否处于过渡状态。import React, { useState, useTransition } from 'react';
function MyComponent() {
const [isPending, startTransition] = useTransition();
const [value, setValue] = useState('');
const handleChange = (event) => {
const newValue = event.target.value;
startTransition(() => {
setValue(newValue); // 标记为非紧急更新
});
};
return (
<div>
<input type="text" onChange={handleChange} />
{isPending && <span>Loading...</span>}
<p>{value}</p>
</div>
);
}
Suspense
,它的作用是什么?答案解析:
Suspense
是 React 16.6 引入的特性,用于处理异步操作(如懒加载组件)的加载状态。它允许开发者定义一个后备 UI,当等待的内容还未加载时,显示该 UI。
用法:
Suspense
包裹需要懒加载的组件,并提供一个 fallback
属性。import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
作用:
useDeferredValue
Hook。答案解析:
useDeferredValue
是 React 18 引入的 Hook,用于处理非紧急更新。当需要更新的状态不那么紧急时,可以使用此 Hook。它允许开发者将某些状态的更新延迟到浏览器空闲时进行,避免阻塞用户交互。
用法:
import React, { useState, useDeferredValue } from 'react';
function MyComponent() {
const [inputValue, setInputValue] = useState('');
const deferredValue = useDeferredValue(inputValue);
return (
<div>
<input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
<p>Deferred Value: {deferredValue}</p>
</div>
);
}
答案解析:
Redux 是一个流行的状态管理库,适用于复杂应用的状态管理。使用 Redux 的步骤包括创建 store、定义 reducer、创建 action 和连接 React 组件。
步骤:
安装 Redux 和 React-Redux。
npm install redux react-redux
创建 Redux store。
import { createStore } from 'redux';
const initialState = { count: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
}
const store = createStore(counterReducer);
Provider
包裹应用。import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
useSelector
和 useDispatch
。import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
}
useLayoutEffect
Hook。答案解析:
useLayoutEffect
是一个 Hook,类似于 useEffect
,但它在 DOM 更新后、浏览器绘制之前同步执行。它适用于需要读取 DOM 布局并同步触发重渲染的场景。
用法:
import React, { useLayoutEffect, useRef } from 'react';
function MyComponent() {
const divRef = useRef();
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
console.log('Element size:', rect);
}, []); // 依赖数组为空,表示只在挂载时执行
return <div ref={divRef}>Measure Me!</div>;
}
答案解析:
表单验证可以通过状态管理和条件渲染来实现。可以在输入框的 onChange
事件中进行验证,然后根据验证结果更新状态,显示错误消息。
示例:
import React, { useState } from 'react';
function MyForm() {
const [value, setValue] = useState('');
const [error, setError] = useState('');
const handleChange = (event) => {
const newValue = event.target.value;
setValue(newValue);
if (newValue.length < 3) {
setError('Input must be at least 3 characters long.');
} else {
setError('');
}
};
return (
<div>
<input type="text" value={value} onChange={handleChange} />
{error && <span style={{ color: 'red' }}>{error}</span>}
</div>
);
}
答案解析:
文件上传可以通过 实现,并在
onChange
事件中读取文件信息。可以使用 FileReader
API 读取文件内容。
示例:
import React, { useState } from 'react';
function FileUpload() {
const [file, setFile] = useState(null);
const [fileContent, setFileContent] = useState('');
const handleChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
const reader = new FileReader();
reader.onload = () => {
setFileContent(reader.result);
};
reader.readAsText(selectedFile); // 读取文件内容
};
return (
<div>
<input type="file" onChange={handleChange} />
{file && <p>Selected file: {file.name}</p>}
{fileContent && <pre>{fileContent}</pre>}
</div>
);
}
答案解析:
自定义 Hooks 是一种复用逻辑的方式,可以将组件中的逻辑提取到函数中。自定义 Hook 必须以 use
开头。
示例:
import { useState, useEffect } from 'react';
// 自定义 Hook
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch(url);
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
}, [url]);
return { data, loading };
}
// 在组件中使用自定义 Hook
function MyComponent() {
const { data, loading } = useFetch('https://api.example.com/data');
if (loading) {
return <div>Loading...</div>;
}
return <div>{JSON.stringify(data)}</div>;
}
答案解析:
在 React 应用中,可以使用 .env
文件定义环境变量。变量名必须以 REACT_APP_
开头。
步骤:
.env
文件。REACT_APP_API_URL=https://api.example.com
function App() {
const apiUrl = process.env.REACT_APP_API_URL;
return <div>API URL: {apiUrl}</div>;
}
环境变量在构建时被替换,因此在生产环境中也能正常使用。
答案解析:
React 的生命周期方法用于控制组件的创建、更新和卸载过程。主要分为三个阶段:挂载、更新和卸载。
挂载阶段:
constructor
: 初始化状态和绑定方法。static getDerivedStateFromProps
: 在渲染之前,根据 props 更新 state。render
: 渲染 UI。componentDidMount
: 组件挂载后调用,适合进行 API 请求或订阅。更新阶段:
static getDerivedStateFromProps
: 在更新时根据新的 props 更新 state。shouldComponentUpdate
: 根据新的 props 和 state 判断是否重新渲染。render
: 重新渲染 UI。getSnapshotBeforeUpdate
: 在 DOM 更新前获取快照。componentDidUpdate
: 更新后调用,适合进行 DOM 操作或网络请求。卸载阶段:
componentWillUnmount
: 组件卸载前调用,适合清理订阅和定时器。示例:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
console.log('Component mounted');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component updated');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <div>{this.state.count}</div>;
}
}
答案解析:
条件渲染可以使用 JavaScript 的条件语句,如 if
语句、三元运算符或逻辑与运算符 (&&
) 来实现。
function MyComponent({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please log in.</h1>;
}
}
function MyComponent({ isLoggedIn }) {
return (
<h1>{isLoggedIn ? 'Welcome back!' : 'Please log in.'}</h1>
);
}
function MyComponent({ isLoggedIn }) {
return (
<div>
{isLoggedIn && <h1>Welcome back!</h1>}
{!isLoggedIn && <h1>Please log in.</h1>}
</div>
);
}
答案解析:
键盘事件可以通过在组件中添加 onKeyDown
、onKeyPress
和 onKeyUp
事件处理程序来处理。这些事件可以用于捕获用户的键盘输入。
示例:
import React, { useState } from 'react';
function KeyPressComponent() {
const [keyPressed, setKeyPressed] = useState('');
const handleKeyDown = (event) => {
setKeyPressed(event.key);
};
return (
<div tabIndex={0} onKeyDown={handleKeyDown}>
<p>Press any key!</p>
{keyPressed && <p>You pressed: {keyPressed}</p>}
</div>
);
}
useDebugValue
Hook 的使用场景。答案解析:
useDebugValue
是一个 Hook,用于在 React 开发工具中显示调试信息,特别是在自定义 Hook 中。它可以帮助开发者更好地理解 Hook 的状态。
示例:
import { useState, useEffect, useDebugValue } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch(url);
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
}, [url]);
// 使用 useDebugValue 为调试提供信息
useDebugValue(loading ? 'Loading...' : 'Loaded');
return { data, loading };
}
function MyComponent() {
const { data, loading } = useFetch('https://api.example.com/data');
return (
<div>
{loading ? 'Loading...' : JSON.stringify(data)}
</div>
);
}
答案解析:
回调函数用于在子组件中触发父组件的操作。可以通过 props 将父组件的函数传递给子组件,子组件在某些事件发生时调用。
示例:
function Parent() {
const handleChildClick = () => {
alert('Child was clicked!');
};
return <Child onClick={handleChildClick} />;
}
function Child({ onClick }) {
return <button onClick={onClick}>Click me!</button>;
}
答案解析:
动态列表可以通过将数据存储在状态中,并使用 map
方法渲染列表项。可以使用输入框和按钮来添加新的列表项。
示例:
import React, { useState } from 'react';
function DynamicList() {
const [items, setItems] = useState([]);
const [inputValue, setInputValue] = useState('');
const handleAddItem = () => {
setItems([...items, inputValue]);
setInputValue('');
};
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleAddItem}>Add Item</button>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
useReducer
的使用场景。答案解析:
useReducer
是一个 Hook,适用于管理复杂状态或多个子状态的场景。它类似于 Redux 的 reducer,适合处理复杂的状态逻辑。
示例:
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
答案解析:
国际化可以通过使用第三方库(如 react-i18next
)来实现。该库提供了简单的 API 来管理多语言支持。
步骤:
安装 react-i18next
和 i18next
:
npm install react-i18next i18next
配置 i18next:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
resources: {
en: {
translation: {
welcome: "Welcome to React",
},
},
fr: {
translation: {
welcome: "Bienvenue à React",
},
},
},
lng: "en", // 默认语言
fallbackLng: "en",
interpolation: {
escapeValue: false,
},
});
useTranslation
Hook:import React from 'react';
import { useTranslation } from 'react-i18next';
function App() {
const { t } = useTranslation();
return <h1>{t('welcome')}</h1>;
}
答案解析:
Suspense
与 React.lazy
结合使用,可以实现组件的懒加载及加载状态的反馈。当组件被懒加载时,Suspense
会显示 fallback UI,直到组件加载完成。
示例:
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading component...</div>}>
<LazyComponent />
</Suspense>
);
}
答案解析:
ref
是 React 提供的一个特殊属性,用于直接访问 DOM 元素或类组件的实例。可以使用 React.createRef()
或 useRef
Hook 创建 ref。
示例:
createRef
:class MyComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
focusInput = () => {
this.inputRef.current.focus();
};
render() {
return (
<>
<input ref={this.inputRef} type="text" />
<button onClick={this.focusInput}>Focus Input</button>
</>
);
}
}
useRef
:import React, { useRef } from 'react';
function MyComponent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
forwardRef
,如何使用它?答案解析:
forwardRef
是一个高阶组件,允许将 ref 转发到子组件,使父组件能够直接访问子组件的 DOM 元素或类实例。
示例:
import React, { forwardRef, useRef } from 'react';
const FancyInput = forwardRef((props, ref) => (
<input ref={ref} type="text" className="fancy-input" />
));
function Parent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // 直接访问子组件的输入框
};
return (
<>
<FancyInput ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
答案解析:
CSS-in-JS 是一种在 JavaScript 中编写 CSS 的方式,允许动态样式和组件化风格。常用的 CSS-in-JS 库有:
import styled from 'styled-components';
const Button = styled.button`
background-color: blue;
color: white;
padding: 10px;
`;
function App() {
return <Button>Click Me</Button>;
}
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
const buttonStyle = css`
background-color: green;
color: white;
padding: 10px;
`;
function App() {
return <button css={buttonStyle}>Click Me</button>;
}
import { createUseStyles } from 'react-jss';
const useStyles = createUseStyles({
button: {
backgroundColor: 'red',
color: 'white',
padding: '10px',
},
});
function App() {
const classes = useStyles();
return <button className={classes.button}>Click Me</button>;
}
答案解析:
可以使用 HTML5 的拖放 API 或者第三方库(如 react-beautiful-dnd
或 react-dnd
)实现拖放功能。
使用 HTML5 拖放 API 的示例:
import React, { useState } from 'react';
function DraggableItem({ item }) {
const handleDragStart = (event) => {
event.dataTransfer.setData('text/plain', item);
};
return (
<div draggable onDragStart={handleDragStart}>
{item}
</div>
);
}
function DroppableArea() {
const [droppedItem, setDroppedItem] = useState(null);
const handleDrop = (event) => {
event.preventDefault();
const data = event.dataTransfer.getData('text');
setDroppedItem(data);
};
const handleDragOver = (event) => {
event.preventDefault();
};
return (
<div onDrop={handleDrop} onDragOver={handleDragOver} style={{ border: '1px solid black', height: '200px' }}>
{droppedItem ? <div>Dropped: {droppedItem}</div> : 'Drop here!'}
</div>
);
}
function App() {
return (
<div>
<DraggableItem item="Item 1" />
<DroppableArea />
</div>
);
}
useImperativeHandle
Hook。答案解析:
useImperativeHandle
是一个 Hook,允许自定义暴露给父组件的实例值。常与 forwardRef
一起使用,使父组件可以调用子组件的方法或访问其状态。
示例:
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
const MyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
},
}));
return <input ref={inputRef} type="text" />;
});
function Parent() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus();
};
const handleGetValue = () => {
alert(inputRef.current.getValue());
};
return (
<>
<MyInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleGetValue}>Get Input Value</button>
</>
);
}
答案解析:
在 React 中使用 WebSocket 可以通过创建 WebSocket 连接并在组件中处理消息。通常在 useEffect
中建立连接,并在组件卸载时清理。
示例:
import React, { useEffect, useState } from 'react';
function WebSocketComponent() {
const [messages, setMessages] = useState([]);
const [inputValue, setInputValue] = useState('');
let socket;
useEffect(() => {
socket = new WebSocket('ws://your-websocket-url');
socket.onmessage = (event) => {
setMessages((prev) => [...prev, event.data]);
};
return () => {
socket.close(); // 清理连接
};
}, []);
const handleSendMessage = () => {
socket.send(inputValue);
setInputValue('');
};
return (
<div>
<div>
{messages.map((msg, index) => (
<div key={index}>{msg}</div>
))}
</div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleSendMessage}>Send</button>
</div>
);
}
useMemo
的使用场景。答案解析:
useMemo
是一个 Hook,用于缓存计算结果,避免在每次渲染时重新计算。适用于性能优化,尤其是在处理复杂计算或依赖于大量数据的场景。
示例:
import React, { useMemo, useState } from 'react';
function MyComponent({ items }) {
const [filter, setFilter] = useState('');
const filteredItems = useMemo(() => {
return items.filter(item => item.includes(filter));
}, [items, filter]); // 仅在 items 或 filter 变化时重新计算
return (
<div>
<input
type="text"
value={filter}
onChange={(e) => setFilter(e.target.value)}
/>
<ul>
{filteredItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
答案解析:
图像上传可以通过 元素实现,并在
onChange
事件中处理文件选择。可以使用 FileReader
API 读取并预览图像。
示例:
import React, { useState } from 'react';
function ImageUpload() {
const [image, setImage] = useState(null);
const handleChange = (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onloadend = () => {
setImage(reader.result); // 设置图像预览
};
if (file) {
reader.readAsDataURL(file); // 读取文件
}
};
return (
<div>
<input type="file" accept="image/*" onChange={handleChange} />
{image && <img src={image} alt="Preview" style={{ width: '200px' }} />}
</div>
);
}
createContext
和 Context.Provider
。答案解析:
createContext
用于创建上下文对象,Context.Provider
用于提供该上下文的值。上下文可以在组件树中共享数据,无需通过 props 层层传递。
示例:
import React, { createContext, useContext } from 'react';
// 创建上下文
const MyContext = createContext();
function ProviderComponent() {
return (
<MyContext.Provider value="Hello, Context!">
<ChildComponent />
</MyContext.Provider>
);
}
function ChildComponent() {
const value = useContext(MyContext); // 访问上下文值
return <div>{value}</div>;
}
useCallback
Hook?答案解析:
useCallback
Hook 用于缓存一个函数的引用,避免在每次渲染时重新创建函数。适合将回调函数传递给子组件时,防止不必要的重新渲染。
示例:
import React, { useState, useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // 依赖数组为空,函数只在第一次渲染时创建
return (
<div>
<Child onClick={increment} />
<p>Count: {count}</p>
</div>
);
}
function Child({ onClick }) {
console.log('Child rendered');
return <button onClick={onClick}>Increment</button>;
}
答案解析:
模态框可以通过条件渲染和 CSS 来实现。可以创建一个组件,使用状态来控制模态框的可见性。
示例:
import React, { useState } from 'react';
function Modal({ isOpen, onClose }) {
if (!isOpen) return null;
return (
<div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,0.5)' }}>
<div style={{ background: 'white', margin: '100px auto', padding: '20px', width: '300px' }}>
<h2>Modal Title</h2>
<p>Modal Content</p>
<button onClick={onClose}>Close</button>
</div>
</div>
);
}
function App() {
const [isModalOpen, setModalOpen] = useState(false);
return (
<div>
<button onClick={() => setModalOpen(true)}>Open Modal</button>
<Modal isOpen={isModalOpen} onClose={() => setModalOpen(false)} />
</div>
);
}
useEffect
的依赖数组。答案解析:
useEffect
的依赖数组用于控制副作用的执行时机。当依赖数组中的值发生变化时,副作用将重新执行。可以通过传递空数组 []
来仅在组件挂载时执行一次。
示例:
import React, { useEffect, useState } from 'react';
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return () => clearInterval(interval); // 清理定时器
}, []); // 仅在组件挂载时执行
return <div>Count: {count}</div>;
}
答案解析:
受控组件通过将输入元素的值与 React 状态绑定,使用 onChange
事件更新状态。这样可以确保输入的值始终与状态相匹配。
示例:
import React, { useState } from 'react';
function ControlledForm() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<form>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Current Value: {inputValue}</p>
</form>
);
}
React.memo
的使用场景。答案解析:
React.memo
是一个高阶组件,用于优化组件性能。它仅在 props 变化时重新渲染组件。适用于功能组件,特别是在组件接收复杂的 props 时。
示例:
import React from 'react';
// 使用 React.memo 包裹组件
const MyComponent = React.memo(({ name }) => {
console.log('Rendering:', name);
return <div>{name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<MyComponent name="Alice" />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
答案解析:
高阶组件是一个函数,它接收一个组件并返回一个新的组件。HOC 常用于复用组件逻辑和状态。
示例:
import React from 'react';
// 创建高阶组件
const withCounter = (WrappedComponent) => {
return class extends React.Component {
state = { count: 0 };
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<WrappedComponent
count={this.state.count}
increment={this.increment}
{...this.props}
/>
);
}
};
};
// 使用高阶组件
const DisplayCount = ({ count, increment }) => (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
const EnhancedComponent = withCounter(DisplayCount);
React.StrictMode
的作用。答案解析:
React.StrictMode
是一个工具,用于帮助发现潜在问题。它不会渲染任何 UI,但会激活额外的检查和警告,以确保组件遵循最佳实践。
用途:
示例:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <h1>Hello, World!</h1>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
useRef
Hook?答案解析:
useRef
是一个 Hook,用于创建一个可变的引用对象,该对象在组件重新渲染时不会改变。适合用于访问 DOM 元素或保存任意值。
示例:
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus(); // 访问 DOM 元素
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
useLayoutEffect
的使用场景。答案解析:
useLayoutEffect
类似于 useEffect
,但它在 DOM 更新后、浏览器绘制之前执行。适用于需要同步读取 DOM 布局并在绘制之前进行更改的场景。
示例:
import React, { useLayoutEffect, useRef } from 'react';
function LayoutEffectComponent() {
const divRef = useRef();
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
console.log('Element size:', rect);
}, []); // 仅在组件挂载时执行
return <div ref={divRef}>Measure Me!</div>;
}
答案解析:
服务端渲染(SSR)是指在服务器上渲染 React 组件并将 HTML 发送到客户端。可以使用 Next.js
等框架来简化 SSR 的实现。
基本步骤:
创建一个 Next.js 项目。
npx create-next-app my-app
在 pages
目录中创建页面组件。
// pages/index.js
import React from 'react';
function HomePage() {
return <h1>Welcome to Next.js!</h1>;
}
export default HomePage;
npm run dev
答案解析:
状态提升是指将共享状态提升到最近的公共父组件,以便多个子组件能够访问和控制该状态。通常涉及将状态和更新函数通过 props 传递给子组件。
示例:
import React, { useState } from 'react';
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child count={count} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
function Child({ count }) {
return <p>Count from Parent: {count}</p>;
}
key
属性的作用。答案解析:
key
属性用于标识列表中每个元素的唯一性。React 使用 key
来优化渲染性能,帮助识别哪些元素发生了变化、添加或删除。使用唯一的 key
可以提高性能并避免状态问题。
示例:
const items = ['apple', 'banana', 'orange'];
function ItemList() {
return (
<ul>
{items.map((item) => (
<li key={item}>{item}</li> // 使用唯一标识符作为 key
))}
</ul>
);
}
使用 key
时,避免使用数组索引作为 key,因为这可能导致性能问题和状态不一致的问题。
答案解析:
懒加载是一种优化技术,在需要时才加载组件或资源,而不是在应用启动时加载所有内容。React 提供了 React.lazy
和 Suspense
来实现组件的懒加载。
示例:
import React, { Suspense, lazy } from 'react';
// 使用 React.lazy 动态导入组件
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
useTransition
Hook。答案解析:
useTransition
是 React 18 引入的 Hook,用于在渲染过程中标记某些状态更新为非紧急状态。允许 React 优先处理更紧急的更新,从而改善用户体验。
示例:
import React, { useState, useTransition } from 'react';
function MyComponent() {
const [isPending, startTransition] = useTransition();
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
const newValue = event.target.value;
startTransition(() => {
setInputValue(newValue); // 标记为非紧急更新
});
};
return (
<div>
<input type="text" onChange={handleChange} />
{isPending && <span>Loading...</span>}
<p>{inputValue}</p>
</div>
);
}
useDeferredValue
?答案解析:
useDeferredValue
是 React 18 引入的 Hook,用于处理不紧急的更新。允许开发者将某些状态的更新延迟到浏览器空闲时进行,避免阻塞用户交互。
示例:
import React, { useState, useDeferredValue } from 'react';
function MyComponent() {
const [inputValue, setInputValue] = useState('');
const deferredValue = useDeferredValue(inputValue);
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<p>Deferred Value: {deferredValue}</p>
</div>
);
}
useImperativeHandle
Hook 的用途。答案解析:
useImperativeHandle
是一个 Hook,允许自定义暴露给父组件的实例值。常与 forwardRef
一起使用,使父组件可以调用子组件的方法或访问其属性。
示例:
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
const MyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
},
}));
return <input ref={inputRef} type="text" />;
});
function Parent() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus();
};
const handleGetValue = () => {
alert(inputRef.current.getValue());
};
return (
<>
<MyInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleGetValue}>Get Input Value</button>
</>
);
}
答案解析:
非受控组件是指使用 ref
直接访问 DOM 元素的方式,而不是将其值存储在 React 状态中。适合处理简单的表单。
示例:
import React, { useRef } from 'react';
function UncontrolledForm() {
const inputRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
alert('Input value: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
Error Boundaries
。答案解析:
错误边界是 React 组件的一个特性,用于捕获子组件树中的 JavaScript 错误,并防止整个应用崩溃。错误边界组件实现了 componentDidCatch
和 getDerivedStateFromError
方法。
示例:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true }; // 更新状态以显示备用 UI
}
componentDidCatch(error, info) {
console.error('Error caught:', error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children; // 正常渲染子组件
}
}
// 使用 Error Boundary
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
答案解析:
主题切换可以通过上下文 API 和状态管理来实现,允许在整个应用中共享主题状态。
示例:
import React, { createContext, useContext, useState } from 'react';
// 创建上下文
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
<p>{`Current theme: ${theme}`}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
useFetch
自定义 Hook?答案解析:
useFetch
是一个自定义 Hook,用于处理 API 请求和数据获取,简化组件中的数据获取逻辑。
示例:
import React, { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// 在组件中使用自定义 Hook
function MyComponent() {
const { data, loading, error } = useFetch('https://api.example.com/data');
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>{JSON.stringify(data)}</div>;
}
useMemo
和 useCallback
的区别。答案解析:
useMemo
:用于缓存计算结果,避免在每次渲染时重新计算。适合处理复杂计算或依赖于大量数据的场景。const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
:用于缓存函数的引用,避免在每次渲染时重新创建函数。适合将回调函数传递给子组件时,防止不必要的重新渲染。const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useEffect
处理订阅?答案解析:
useEffect
可以用于处理订阅功能,例如 WebSocket 或数据流。在组件挂载时设置订阅,并在组件卸载时清理。
示例:
import React, { useEffect, useState } from 'react';
function SubscriptionComponent() {
const [data, setData] = useState(null);
useEffect(() => {
const subscription = subscribeToData((newData) => {
setData(newData);
});
return () => {
subscription.unsubscribe(); // 清理订阅
};
}, []); // 仅在组件挂载时执行
return <div>{data ? `Data: ${data}` : 'Waiting for data...'}</div>;
}
// 模拟订阅的函数
function subscribeToData(callback) {
const interval = setInterval(() => {
callback(Math.random());
}, 1000);
return {
unsubscribe: () => clearInterval(interval), // 取消订阅
};
}
onClick
事件?答案解析:
在 React 中,可以通过将事件处理函数绑定到组件的元素上来处理点击事件。通常使用箭头函数来确保 this
的上下文正确。
示例:
import React from 'react';
function ClickComponent() {
const handleClick = () => {
alert('Button clicked!');
};
return <button onClick={handleClick}>Click Me</button>;
}
useContext
Hook 的使用。答案解析:
useContext
Hook 允许组件访问上下文中的值。它接受一个上下文对象并返回当前上下文的值,适合在组件树中共享数据。
示例:
import React, { createContext, useContext } from 'react';
// 创建上下文
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const theme = 'dark';
return (
<ThemeContext.Provider value={theme}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const theme = useContext(ThemeContext); // 获取上下文值
return <div>{`Current theme is ${theme}`}</div>;
}
function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
答案解析:
可以通过 onChange
事件来处理输入框的变化,并将输入的值存储在组件的状态中。
示例:
import React, { useState } from 'react';
function InputComponent() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Current Input: {inputValue}</p>
</div>
);
}
forwardRef
用法。答案解析:
forwardRef
是一个高阶组件,用于将 ref
转发到子组件,使父组件能够直接访问子组件的 DOM 元素或类实例。
示例:
import React, { forwardRef, useRef } from 'react';
const FancyInput = forwardRef((props, ref) => (
<input ref={ref} type="text" />
));
function Parent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus(); // 直接访问子组件的输入框
};
return (
<>
<FancyInput ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
React.StrictMode
?答案解析:
React.StrictMode
是一个帮助开发者发现潜在问题的工具。它不会渲染任何 UI,但会激活额外的检查和警告,帮助识别不安全的生命周期方法和过时的 API。
示例:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <h1>Hello, World!</h1>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
答案解析:
条件渲染可以通过 JavaScript 的条件语句、三元运算符或逻辑与运算符(&&
)来实现,根据条件返回不同的 JSX 结构。
示例:
import React from 'react';
function ConditionalComponent({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please log in.</h1>}
</div>
);
}
useDebugValue
Hook。答案解析:
useDebugValue
是一个 Hook,用于在 React 开发工具中显示调试信息。通常在自定义 Hook 中使用,帮助开发者更好地理解状态。
示例:
import { useState, useEffect, useDebugValue } from 'react';
function useCustomHook(value) {
const [state, setState] = useState(value);
useEffect(() => {
// 逻辑处理
}, [value]);
// 使用 useDebugValue 提供调试信息
useDebugValue(state ? 'Active' : 'Inactive');
return state;
}
答案解析:
表单验证可以通过状态管理和条件渲染来实现,通常在输入框的 onChange
事件中进行验证,并根据验证结果更新状态。
示例:
import React, { useState } from 'react';
function ValidationForm() {
const [inputValue, setInputValue] = useState('');
const [error, setError] = useState('');
const handleChange = (event) => {
const value = event.target.value;
setInputValue(value);
if (value.length < 3) {
setError('Input must be at least 3 characters long.');
} else {
setError('');
}
};
return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
{error && <span style={{ color: 'red' }}>{error}</span>}
</div>
);
}
useCallback
的用途。答案解析:
useCallback
是一个 Hook,用于缓存函数的引用,避免在每次渲染时重新创建函数。适合将回调函数传递给子组件时,防止不必要的重新渲染。
示例:
import React, { useState, useCallback } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // 依赖数组为空,函数只在第一次渲染时创建
return (
<div>
<Child onClick={increment} />
<p>Count: {count}</p>
</div>
);
}
const Child = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Increment</button>;
});
答案解析:
状态提升是指将共享状态提升到最近的公共父组件,以便多个子组件能够访问和控制该状态。通常涉及将状态和更新函数通过 props 传递给子组件。
示例:
import React, { useState } from 'react';
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<Child count={count} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
function Child({ count }) {
return <p>Count from Parent: {count}</p>;
}
useEffect
进行数据获取?答案解析:
useEffect
可以用于在组件挂载时执行数据获取操作。可以在 useEffect
中调用 API,并将结果存储在组件的状态中。
示例:
import React, { useState, useEffect } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
setLoading(false);
};
fetchData();
}, []); // 依赖数组为空,表示仅在组件挂载时执行
if (loading) return <div>Loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}
useReducer
Hook 的用法。答案解析:
useReducer
是一个 Hook,用于管理复杂状态。它接受一个 reducer 函数和初始状态,并返回当前状态和 dispatch 函数。
示例:
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
答案解析:
组件的懒加载可以通过 React.lazy
和 Suspense
来实现。React.lazy
可以动态导入组件,而 Suspense
用于处理加载状态。
示例:
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
key
属性的作用。答案解析:
key
属性用于识别列表中每个元素的唯一性。React 使用 key
来优化渲染性能,帮助识别哪些元素发生了变化、添加或删除。key
应该是唯一的,避免使用数组索引作为 key
,因为这可能导致性能问题和状态不一致。
示例:
const items = ['apple', 'banana', 'orange'];
function ItemList() {
return (
<ul>
{items.map((item, index) => (
<li key={item}>{item}</li> // 使用唯一标识符作为 key
))}
</ul>
);
}
useImperativeHandle
Hook?答案解析:
useImperativeHandle
允许自定义暴露给父组件的实例值。通常与 forwardRef
一起使用,使父组件可以调用子组件的方法或访问其状态。
示例:
import React, { useImperativeHandle, forwardRef, useRef } from 'react';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
},
}));
return <input ref={inputRef} type="text" />;
});
function Parent() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus();
};
const handleGetValue = () => {
alert(inputRef.current.getValue());
};
return (
<>
<CustomInput ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
<button onClick={handleGetValue}>Get Input Value</button>
</>
);
}
答案解析:
文件上传可以通过 元素实现,并在
onChange
事件中读取文件信息。可以使用 FileReader
API 读取文件内容。
示例:
import React, { useState } from 'react';
function FileUpload() {
const [file, setFile] = useState(null);
const handleChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
const handleUpload = () => {
const formData = new FormData();
formData.append('file', file);
// 这里可以添加文件上传逻辑
console.log('File ready for upload:', file);
};
return (
<div>
<input type="file" onChange={handleChange} />
{file && <p>Selected file: {file.name}</p>}
<button onClick={handleUpload}>Upload</button>
</div>
);
}
useLayoutEffect
Hook。答案解析:
useLayoutEffect
类似于 useEffect
,但它在 DOM 更新后、浏览器绘制之前执行。适用于需要同步读取 DOM 布局并在绘制之前进行更改的场景。
示例:
import React, { useLayoutEffect, useRef } from 'react';
function LayoutEffectComponent() {
const divRef = useRef();
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
console.log('Element size:', rect);
}, []); // 仅在组件挂载时执行
return <div ref={divRef}>Measure Me!</div>;
}
答案解析:
主题切换可以通过上下文 API 和状态管理来实现,允许在整个应用中共享主题状态。
示例:
import React, { createContext, useContext, useState } from 'react';
// 创建上下文
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
<p>{`Current theme: ${theme}`}</p>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
React.memo
?答案解析:
React.memo
是一个高阶组件,用于优化组件性能。它仅在 props 变化时重新渲染组件。适用于功能组件,特别是在组件接收复杂的 props 时。
示例:
import React from 'react';
// 使用 React.memo 包裹组件
const MyComponent = React.memo(({ name }) => {
console.log('Rendering:', name);
return <div>{name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<MyComponent name="Alice" />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useMemo
和 useCallback
的区别。答案解析:
useMemo
:用于缓存计算结果,避免在每次渲染时重新计算。适合处理复杂计算或依赖于大量数据的场景。const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback
:用于缓存函数的引用,避免在每次渲染时重新创建函数。适合将回调函数传递给子组件时,防止不必要的重新渲染。const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
答案解析:
受控组件通过将表单元素的值与 React 状态绑定来实现,而非受控组件则使用 ref
直接访问 DOM 元素的值。
import React, { useState } from 'react';
function ControlledForm() {
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
setInputValue(event.target.value);
};
return (
<form>
<input type="text" value={inputValue} onChange={handleChange} />
<p>Current Value: {inputValue}</p>
</form>
);
}
import React, { useRef } from 'react';
function UncontrolledForm() {
const inputRef = useRef();
const handleSubmit = (event) => {
event.preventDefault();
alert('Input value: ' + inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}
createRef
和 useRef
的区别。答案解析:
createRef
:用于类组件,创建一个可以附加到 React 元素的 ref 对象。class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
focusInput = () => {
this.inputRef.current.focus();
};
render() {
return (
<>
<input ref={this.inputRef} type="text" />
<button onClick={this.focusInput}>Focus Input</button>
</>
);
}
}
useRef
:用于函数组件,创建一个可变的 ref 对象,且在组件的生命周期中保持不变。import React, { useRef } from 'react';
function MyFunctionComponent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</>
);
}
答案解析:
可以使用 HTML5 的拖放 API 实现拖放功能。通过设置事件处理程序来处理拖动和放置。
示例:
import React, { useState } from 'react';
function DraggableItem({ item }) {
const handleDragStart = (event) => {
event.dataTransfer.setData('text/plain', item);
};
return (
<div draggable onDragStart={handleDragStart}>
{item}
</div>
);
}
function DroppableArea() {
const [droppedItem, setDroppedItem] = useState(null);
const handleDrop = (event) => {
event.preventDefault();
const data = event.dataTransfer.getData('text/plain');
setDroppedItem(data);
};
const handleDragOver = (event) => {
event.preventDefault(); // 允许放置
};
return (
<div onDrop={handleDrop} onDragOver={handleDragOver} style={{ border: '1px solid black', height: '200px', marginTop: '20px' }}>
{droppedItem ? <div>Dropped: {droppedItem}</div> : 'Drop here!'}
</div>
);
}
function App() {
return (
<div>
<DraggableItem item="Drag me!" />
<DroppableArea />
</div>
);
}
useDebugValue
的使用场景。答案解析:
useDebugValue
是一个 Hook,用于在 React 开发者工具中显示调试信息。通常在自定义 Hook 中使用,帮助开发者更好地理解状态和逻辑。
示例:
import React, { useState, useEffect, useDebugValue } from 'react';
function useCustomHook(value) {
const [state, setState] = useState(value);
useEffect(() => {
// 一些逻辑处理
}, [value]);
useDebugValue(state ? 'Active' : 'Inactive'); // 显示调试信息
return state;
}
答案解析:
状态管理可以通过使用 useState
、useReducer
、或第三方库(如 Redux 或 MobX)来实现。选择适合项目复杂度和需求的状态管理方案。
useState
:import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useReducer
:import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
// 安装 Redux 和 React-Redux
// npm install redux react-redux
import { createStore } from 'redux';
import { Provider, useSelector, useDispatch } from 'react-redux';
const initialState = { count: 0 };
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
};
const store = createStore(reducer);
function Counter() {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
React.Fragment
?答案解析:
React.Fragment
是一个可以用来包裹多个子元素而不添加额外节点的组件。它可以帮助简化组件的结构,避免不必要的 DOM 元素。
示例:
import React from 'react';
function FragmentExample() {
return (
<React.Fragment>
<h1>Title</h1>
<p>Description</p>
</React.Fragment>
);
}
// 也可以使用简写语法
function FragmentExampleShort() {
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
}
答案解析:
React 的生命周期方法用于控制组件的创建、更新和卸载过程。主要分为三个阶段:
挂载:
constructor
: 初始化状态和绑定方法。render
: 渲染 UI。componentDidMount
: 组件挂载后调用,适合进行 API 请求或订阅。更新:
shouldComponentUpdate
: 根据新的 props 和 state 判断是否重新渲染。render
: 重新渲染 UI。componentDidUpdate
: 更新后调用,适合进行 DOM 操作或网络请求。卸载:
componentWillUnmount
: 组件卸载前调用,适合清理订阅和定时器。示例:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
console.log('Component mounted');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component updated');
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return <div>{this.state.count}</div>;
}
}
useEffect
清理副作用?答案解析:
在 useEffect
中可以返回一个清理函数,用于在组件卸载时或在依赖项变化时清理副作用,比如清理订阅、定时器等。
示例:
import React, { useEffect, useState } from 'react';
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return () => clearInterval(interval); // 清理定时器
}, []); // 仅在组件挂载时执行
return <div>Count: {count}</div>;
}
答案解析:
CSS Modules 是一种将 CSS 作用域限制在组件中的方法,避免全局 CSS 冲突。需要在构建工具中启用 CSS Modules 支持。
示例:
/* styles.module.css */
.container {
background-color: blue;
color: white;
}
import React from 'react';
import styles from './styles.module.css';
function StyledComponent() {
return <div className={styles.container}>Hello, CSS Modules!</div>;
}
答案解析:
错误边界是 React 组件的一个特性,用于捕获子组件树中的 JavaScript 错误,并防止整个应用崩溃。错误边界组件实现了 componentDidCatch
和 getDerivedStateFromError
方法。
示例:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true }; // 更新状态以显示备用 UI
}
componentDidCatch(error, info) {
console.error('Error caught:', error, info);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children; // 正常渲染子组件
}
}
// 使用 Error Boundary
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
答案解析:
防抖是一种控制函数执行频率的技术。可以使用 setTimeout
实现防抖功能,通常在输入框的 onChange
事件中使用。
示例:
import React, { useState } from 'react';
function DebounceInput() {
const [value, setValue] = useState('');
const [debouncedValue, setDebouncedValue] = useState('');
const handleChange = (event) => {
setValue(event.target.value);
// 设置防抖
clearTimeout(window.debounceTimeout);
window.debounceTimeout = setTimeout(() => {
setDebouncedValue(event.target.value);
}, 300);
};
return (
<div>
<input type="text" value={value} onChange={handleChange} />
<p>Debounced Value: {debouncedValue}</p>
</div>
);
}
答案解析:
节流是一种限制函数执行频率的技术,可以使用 setTimeout
来实现。适合处理频繁触发的事件,如滚动或窗口调整大小。
示例:
import React, { useEffect, useState } from 'react';
function ThrottleComponent() {
const [count, setCount] = useState(0);
const handleScroll = () => {
setCount((prevCount) => prevCount + 1);
};
useEffect(() => {
const throttledScroll = throttle(handleScroll, 1000);
window.addEventListener('scroll', throttledScroll);
return () => {
window.removeEventListener('scroll', throttledScroll);
};
}, []);
const throttle = (fn, delay) => {
let lastTime = 0;
return function (...args) {
const now = new Date().getTime();
if (now - lastTime >= delay) {
lastTime = now;
fn.apply(this, args);
}
};
};
return <div>Scroll Count: {count}</div>;
}
答案解析:
懒加载和代码分割可以通过 React.lazy
和 Suspense
实现。React.lazy
动态导入组件,Suspense
用于处理加载状态。
示例:
import React, { Suspense, lazy } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
useTransition
Hook。答案解析:
useTransition
是 React 18 引入的 Hook,用于在渲染过程中标记某些状态更新为非紧急状态。允许 React 优先处理更紧急的更新,从而改善用户体验。
示例:
import React, { useState, useTransition } from 'react';
function MyComponent() {
const [isPending, startTransition] = useTransition();
const [inputValue, setInputValue] = useState('');
const handleChange = (event) => {
const newValue = event.target.value;
startTransition(() => {
setInputValue(newValue); // 标记为非紧急更新
});
};
return (
<div>
<input type="text" onChange={handleChange} />
{isPending && <span>Loading...</span>}
<p>{inputValue}</p>
</div>
);
}
useDeferredValue
?答案解析:
useDeferredValue
是 React 18 引入的 Hook,用于处理不紧急的更新。可以将某些状态的更新延迟到浏览器空闲时进行,从而改善性能。
示例:
import React, { useState, useDeferredValue } from 'react';
function MyComponent() {
const [inputValue, setInputValue] = useState('');
const deferredValue = useDeferredValue(inputValue);
return (
<div>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<p>Deferred Value: {deferredValue}</p>
</div>
);
}
答案解析:
国际化可以通过使用第三方库(如 react-i18next
)来实现。该库提供了简单的 API 来管理多语言支持。
步骤:
安装 react-i18next
和 i18next
:
npm install react-i18next i18next
配置 i18next:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
resources: {
en: {
translation: {
welcome: "Welcome to React",
},
},
fr: {
translation: {
welcome: "Bienvenue à React",
},
},
},
lng: "en", // 默认语言
fallbackLng: "en",
interpolation: {
escapeValue: false,
},
});
useTranslation
Hook:import React from 'react';
import { useTranslation } from 'react-i18next';
function App() {
const { t } = useTranslation();
return <h1>{t('welcome')}</h1>;
}
useEffect
的依赖数组。答案解析:
useEffect
的依赖数组用于控制副作用的执行时机。只有当依赖数组中的值发生变化时,副作用才会重新执行。如果依赖数组为空 []
,则副作用仅在组件挂载时执行一次。
示例:
import React, { useEffect, useState } from 'react';
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount((prevCount) => prevCount + 1);
}, 1000);
return () => clearInterval(interval); // 清理定时器
}, []); // 仅在组件挂载时执行
return <div>Count: {count}</div>;
}
useReducer
进行复杂状态管理?答案解析:
useReducer
是一个用于管理复杂状态的 Hook,适合处理多个子状态或复杂状态逻辑。它接受一个 reducer 函数和初始状态,并返回当前状态和 dispatch 函数。
示例:
import React, { useReducer } from 'react';
const initialState = { count: 0, text: '' };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
return { ...state, count: state.count - 1 };
case 'setText':
return { ...state, text: action.payload };
default:
throw new Error();
}
}
function ComplexCounter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<input
type="text"
value={state.text}
onChange={(e) => dispatch({ type: 'setText', payload: e.target.value })}
/>
<p>Text: {state.text}</p>
</div>
);
}
答案解析:
服务端渲染(SSR)是指在服务器上渲染 React 组件,并将 HTML 发送到客户端。可以使用框架如 Next.js 来简化 SSR 的实现。
基本步骤:
创建一个 Next.js 项目。
npx create-next-app my-app
在 pages
目录中创建页面组件。
// pages/index.js
import React from 'react';
function HomePage() {
return <h1>Welcome to Next.js!</h1>;
}
export default HomePage;
npm run dev
React.memo
的工作原理。答案解析:
React.memo
是一个高阶组件,用于优化函数组件的性能。它通过对比 props 的变化,决定是否重新渲染组件。只有当 props 发生变化时,组件才会重新渲染。
示例:
import React from 'react';
const MyComponent = React.memo(({ name }) => {
console.log('Rendering:', name);
return <div>{name}</div>;
});
function Parent() {
const [count, setCount] = useState(0);
return (
<div>
<MyComponent name="Alice" />
<button onClick={() => setCount(count + 1)}>Increment</button>
<p>Count: {count}</p>
</div>
);
}
答案解析:
在进行 API 请求时,通常需要处理可能发生的错误。可以在 useEffect
中捕获错误,并使用状态来存储错误信息。
示例:
import React, { useEffect, useState } from 'react';
function FetchData() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (error) {
setError(error.message);
}
};
fetchData();
}, []);
if (error) return <div>Error: {error}</div>;
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
useEffect
监听多个依赖项?答案解析:
可以在 useEffect
的依赖数组中包含多个依赖项,当其中任何一个依赖项发生变化时,副作用将重新执行。
示例:
import React, { useEffect, useState } from 'react';
function MultiEffectComponent() {
const [count, setCount] = useState(0);
const [text, setText] = useState('');
useEffect(() => {
console.log(`Count changed: ${count}`);
}, [count]); // 仅当 count 变化时执行
useEffect(() => {
console.log(`Text changed: ${text}`);
}, [text]); // 仅当 text 变化时执行
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<input type="text" onChange={(e) => setText(e.target.value)} />
</div>
);
}
答案解析:
React 使用合成事件系统来处理事件,这是一种跨浏览器的事件处理机制。合成事件是 React 封装的原生事件,提供了统一的 API,并在性能和兼容性上进行了优化。
event.persist()
方法保留事件对象的引用。示例:
import React from 'react';
function ClickComponent() {
const handleClick = (event) => {
event.persist(); // 保留事件对象
setTimeout(() => {
console.log(event.type); // 事件仍然有效
}, 1000);
};
return <button onClick={handleClick}>Click Me</button>;
}
答案解析:
组件之间的通信可以通过 props、上下文 API 或事件处理机制实现。父组件通过 props 向子组件传递数据和回调函数,子组件通过调用这些函数与父组件进行交互。
示例:
import React, { useState } from 'react';
function Parent() {
const [message, setMessage] = useState('');
const handleMessageChange = (newMessage) => {
setMessage(newMessage);
};
return (
<div>
<Child onMessageChange={handleMessageChange} />
<p>Message from Child: {message}</p>
</div>
);
}
function Child({ onMessageChange }) {
return (
<input
type="text"
onChange={(e) => onMessageChange(e.target.value)}
/>
);
}
答案解析:
可以通过内联样式、CSS Modules 或条件类名实现条件样式。根据组件的状态或 props 动态设置样式。
示例:
import React, { useState } from 'react';
import './styles.css'; // 假设有样式文件
function ConditionalStyleComponent() {
const [isActive, setIsActive] = useState(false);
return (
<div>
<button onClick={() => setIsActive(!isActive)}>
Toggle Active
</button>
<div className={isActive ? 'active' : 'inactive'}>
This is a {isActive ? 'active' : 'inactive'} state.
</div>
</div>
);
}
useRef
的常见用法。答案解析:
useRef
是一个 Hook,用于创建一个可变的引用对象,通常用于访问 DOM 元素、保持组件的状态或缓存值。
示例:
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
const handleFocus = () => {
inputRef.current.focus(); // 访问输入框的 DOM 元素
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
React.StrictMode
?答案解析:
React.StrictMode
是一个开发工具,用于帮助发现潜在问题。它不会渲染任何 UI,但会激活额外的检查和警告。
示例:
import React from 'react';
import ReactDOM from 'react-dom';
function App() {
return <h1>Hello, World!</h1>;
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
useLayoutEffect
与 useEffect
?答案解析:
useLayoutEffect
在 DOM 更新后、浏览器绘制之前执行,而 useEffect
在浏览器绘制后执行。useLayoutEffect
适合需要同步读取 DOM 布局并在绘制之前进行更改的场景。
示例:
import React, { useEffect, useLayoutEffect, useRef } from 'react';
function LayoutEffectComponent() {
const divRef = useRef();
useLayoutEffect(() => {
const rect = divRef.current.getBoundingClientRect();
console.log('Layout width:', rect.width);
}, []); // 仅在组件挂载时执行
return <div ref={divRef}>Measure Me!</div>;
}
useMemo
和 useCallback
进行性能优化?答案解析:
useMemo
用于缓存计算结果,useCallback
用于缓存函数的引用。两者都可以防止不必要的重新计算和渲染,从而优化性能。
useMemo
:import React, { useMemo, useState } from 'react';
function ExpensiveComponent({ a, b }) {
const computeExpensiveValue = (a, b) => {
// 假设这是一个耗时的计算
return a + b;
};
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
return <div>Computed Value: {memoizedValue}</div>;
}
useCallback
:import React, { useCallback, useState } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((prevCount) => prevCount + 1);
}, []); // 依赖数组为空,函数只在第一次渲染时创建
return <Child onClick={increment} />;
}
const Child = React.memo(({ onClick }) => {
console.log('Child rendered');
return <button onClick={onClick}>Increment</button>;
});
答案解析:
动态路由可以通过 react-router-dom
库实现。它允许根据 URL 参数渲染不同的组件。
步骤:
安装 react-router-dom
:
npm install react-router-dom
配置路由:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function User({ match }) {
return <h2>User ID: {match.params.id}</h2>;
}
function App() {
return (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/user/:id" component={User} />
</Switch>
</Router>
);
}
答案解析:
分页可以通过维护当前页的状态和总数据量来实现。根据当前页计算要显示的数据。
示例:
import React, { useState } from 'react';
const data = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`);
function Pagination() {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 10;
const handlePageChange = (page) => {
setCurrentPage(page);
};
const startIndex = (currentPage - 1) * itemsPerPage;
const currentItems = data.slice(startIndex, startIndex + itemsPerPage);
return (
<div>
<ul>
{currentItems.map((item) => (
<li key={item}>{item}</li>
))}
</ul>
<div>
{Array.from({ length: Math.ceil(data.length / itemsPerPage) }, (_, i) => (
<button key={i + 1} onClick={() => handlePageChange(i + 1)}>
{i + 1}
</button>
))}
</div>
</div>
);
}
答案解析:
动态表单可以通过维护一个表单字段的状态数组来实现,允许用户添加或删除字段。
示例:
import React, { useState } from 'react';
function DynamicForm() {
const [fields, setFields] = useState([{ value: '' }]);
const handleChange = (index, event) => {
const newFields = [...fields];
newFields[index].value = event.target.value;
setFields(newFields);
};
const addField = () => {
setFields([...fields, { value: '' }]);
};
const removeField = (index) => {
const newFields = fields.filter((_, i) => i !== index);
setFields(newFields);
};
return (
<form>
{fields.map((field, index) => (
<div key={index}>
<input
type="text"
value={field.value}
onChange={(e) => handleChange(index, e)}
/>
<button type="button" onClick={() => removeField(index)}>
Remove
</button>
</div>
))}
<button type="button" onClick={addField}>Add Field</button>
</form>
);
}
答案解析:
可以使用 HTML5 的拖放 API 或第三方库(如 react-beautiful-dnd
)来实现拖放排序功能。
示例(使用 HTML5 API):
import React, { useState } from 'react';
function DraggableList() {
const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
const handleDragStart = (index) => {
const draggedItem = items[index];
const newItems = items.filter((_, i) => i !== index);
setItems(newItems);
setItems((prev) => {
return [...prev.slice(0, index), draggedItem, ...prev.slice(index)];
});
};
return (
<ul>
{items.map((item, index) => (
<li
key={item}
draggable
onDragStart={() => handleDragStart(index)}
>
{item}
</li>
))}
</ul>
);
}
答案解析:
Context API 适用于在组件树中共享数据,避免通过 props 逐层传递。常见场景包括主题管理、用户认证、语言设置等。
示例:
import React, { createContext, useContext, useState } from 'react';
const UserContext = createContext();
function UserProvider({ children }) {
const [user, setUser] = useState(null);
const login = (userData) => setUser(userData);
const logout = () => setUser(null);
return (
<UserContext.Provider value={{ user, login, logout }}>
{children}
</UserContext.Provider>
);
}
function UserProfile() {
const { user } = useContext(UserContext);
return <div>{user ? `Hello, ${user.name}` : 'Please log in.'}</div>;
}
function App() {
return (
<UserProvider>
<UserProfile />
</UserProvider>
);
}
答案解析:
可以使用 async/await
在 useEffect
中处理异步操作,例如数据获取。确保在组件卸载时清理操作。
示例:
import React, { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('https://api.example.com/data');
const result = await response.json();
setData(result);
};
fetchData();
}, []);
return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
答案解析:
组件复用可以通过创建可复用的函数组件、传递 props 和使用高阶组件(HOC)实现。
示例:
import React from 'react';
function Button({ label, onClick }) {
return <button onClick={onClick}>{label}</button>;
}
function App() {
return (
<div>
<Button label="Click Me" onClick={() => alert('Button clicked!')} />
<Button label="Another Button" onClick={() => alert('Another button clicked!')} />
</div>
);
}
答案解析:
CSS-in-JS 是一种将 CSS 直接写入 JavaScript 的方法。可以使用库如 styled-components
或 emotion
。
示例(使用 styled-components):
import React from 'react';
import styled from 'styled-components';
const Button = styled.button`
background-color: blue;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
`;
function App() {
return <Button>Click Me!</Button>;
}
答案解析:
条件渲染可以通过 JavaScript 的条件语句、三元运算符或逻辑与运算符(&&
)来实现。
示例:
import React, { useState } from 'react';
function ConditionalRender() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
return (
<div>
{isLoggedIn ? <h1>Welcome back!</h1> : <h1>Please log in.</h1>}
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
Toggle Login
</button>
</div>
);
}
ref
和 forwardRef
?答案解析:
ref
用于访问 DOM 元素,forwardRef
用于将 ref 转发到子组件。适合需要通过父组件访问子组件的场景。
示例:
import React, { useRef, forwardRef } from 'react';
const Input = forwardRef((props, ref) => {
return <input ref={ref} type="text" />;
});
function Parent() {
const inputRef = useRef();
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<Input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
答案解析:
可以通过在组件中添加 onKeyDown
、onKeyUp
或 onKeyPress
事件处理程序来处理键盘事件。
示例:
import React, { useState } from 'react';
function KeyPressComponent() {
const [keyPressed, setKeyPressed] = useState('');
const handleKeyDown = (event) => {
setKeyPressed(event.key);
};
return (
<div
tabIndex="0"
onKeyDown={handleKeyDown}
style={{ border: '1px solid black', padding: '20px' }}
>
Press any key: {keyPressed}
</div>
);
}