《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux... 。

文章目录
- 一、本文面试题目录
-
-
- [51. 如何在React中实现无限滚动(Infinite Scroll)?](#51. 如何在React中实现无限滚动(Infinite Scroll)?)
- [52. React中的useCallback和useMemo有什么区别?](#52. React中的useCallback和useMemo有什么区别?)
- [53. 什么是React的Context API?如何避免Context导致的性能问题?](#53. 什么是React的Context API?如何避免Context导致的性能问题?)
- [54. 如何在React中实现组件的条件渲染?](#54. 如何在React中实现组件的条件渲染?)
- [55. 如何在React中实现状态持久化?](#55. 如何在React中实现状态持久化?)
- [56. 如何在React中实现状态管理?除了Redux还有哪些方案?](#56. 如何在React中实现状态管理?除了Redux还有哪些方案?)
- [57. 什么是React的StrictMode?它有什么作用?](#57. 什么是React的StrictMode?它有什么作用?)
- [58. 如何在React中优化大型列表渲染性能?](#58. 如何在React中优化大型列表渲染性能?)
- [59. 如何在React中实现暗黑模式(Dark Mode)?](#59. 如何在React中实现暗黑模式(Dark Mode)?)
- [60. 如何在React中实现WebSocket通信?](#60. 如何在React中实现WebSocket通信?)
-
一、本文面试题目录
51. 如何在React中实现无限滚动(Infinite Scroll)?
无限滚动实现方案:
-
基于滚动事件监听:
jsxconst [items, setItems] = useState(initialItems); const [page, setPage] = useState(1); const [isLoading, setIsLoading] = useState(false); useEffect(() => { const handleScroll = () => { if ( window.innerHeight + document.documentElement.scrollTop >= document.documentElement.offsetHeight - 500 && !isLoading ) { setIsLoading(true); fetchMoreData(page + 1).then(newItems => { setItems([...items, ...newItems]); setPage(page + 1); setIsLoading(false); }); } }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, [items, page, isLoading]); return ( <div> {items.map(item => <Item key={item.id} {...item} />)} {isLoading && <div>Loading...</div>} </div> ); -
使用Intersection Observer API:
jsxconst [items, setItems] = useState(initialItems); const [isLoading, setIsLoading] = useState(false); const observer = useRef(null); const loadMoreRef = useCallback(node => { if (isLoading) return; if (observer.current) observer.current.disconnect(); observer.current = new IntersectionObserver(entries => { if (entries[0].isIntersecting) { setIsLoading(true); fetchMoreData().then(newItems => { setItems([...items, ...newItems]); setIsLoading(false); }); } }); if (node) observer.current.observe(node); }, [isLoading, items]); return ( <div> {items.map(item => <Item key={item.id} {...item} />)} <div ref={loadMoreRef}>{isLoading ? 'Loading...' : 'Load more'}</div> </div> );
52. React中的useCallback和useMemo有什么区别?
核心区别:
- useCallback:缓存函数引用,避免组件重新渲染时创建新函数
- useMemo:缓存计算结果,避免重复计算
使用场景:
-
useCallback:
jsxconst memoizedCallback = useCallback( () => doSomething(a, b), [a, b] ); -
useMemo:
jsxconst memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
53. 什么是React的Context API?如何避免Context导致的性能问题?
Context API 用于跨层级传递数据,避免props drilling。
性能优化:
-
拆分Context:
jsx// 分离高频变化和低频变化的context const UserContext = React.createContext(); const ThemeContext = React.createContext(); <UserContext.Provider value={user}> <ThemeContext.Provider value={theme}> <App /> </ThemeContext.Provider> </UserContext.Provider> -
使用useMemo缓存Provider值:
jsxconst themeValue = useMemo(() => ({ theme, setTheme }), [theme]); <ThemeContext.Provider value={themeValue}> {children} </ThemeContext.Provider> -
避免在Provider中使用内联对象:
jsx// 不好的写法 <MyContext.Provider value={{ count, setCount }}> // 优化:使用useMemo缓存对象 const contextValue = useMemo(() => ({ count, setCount }), [count]); <MyContext.Provider value={contextValue}>
54. 如何在React中实现组件的条件渲染?
条件渲染方式:
-
if-else语句:
jsxfunction Greeting(props) { if (props.isLoggedIn) { return <h1>Welcome back!</h1>; } return <h1>Please sign in.</h1>; } -
三元运算符:
jsxreturn ( <div> {isLoading ? ( <Spinner /> ) : ( <Content /> )} </div> ); -
逻辑与运算符(&&):
jsxreturn ( <div> {unreadMessages.length > 0 && ( <h2>You have {unreadMessages.length} unread messages.</h2> )} </div> ); -
状态变量控制:
jsxconst [showComponent, setShowComponent] = useState(false); return ( <div> <button onClick={() => setShowComponent(!showComponent)}> Toggle Component </button> {showComponent && <MyComponent />} </div> );
55. 如何在React中实现状态持久化?
状态持久化实现:
-
localStorage + useEffect:
jsxconst [count, setCount] = useState(() => { const saved = localStorage.getItem('count'); return saved ? JSON.parse(saved) : 0; }); useEffect(() => { localStorage.setItem('count', JSON.stringify(count)); }, [count]); -
自定义Hook封装:
jsxfunction useLocalStorage(key, initialValue) { const [value, setValue] = useState(() => { const saved = localStorage.getItem(key); return saved ? JSON.parse(saved) : initialValue; }); useEffect(() => { localStorage.setItem(key, JSON.stringify(value)); }, [key, value]); return [value, setValue]; } // 使用 const [count, setCount] = useLocalStorage('count', 0);
56. 如何在React中实现状态管理?除了Redux还有哪些方案?
状态管理方案:
-
React内置方案:
useState/useReducer(局部状态)Context API(全局状态)
-
第三方库:
- Redux(复杂应用,单向数据流)
- MobX(响应式状态管理,基于装饰器)
- Zustand(轻量级,函数式API)
- Recoil(Facebook开发,原子化状态)
- Jotai(极简,原子化状态)
-
示例(使用Zustand):
jsximport create from 'zustand'; const useCounterStore = create((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), decrement: () => set((state) => ({ count: state.count - 1 })), })); // 使用store function Counter() { const count = useCounterStore((state) => state.count); const increment = useCounterStore((state) => state.increment); return ( <div> <p>Count: {count}</p> <button onClick={increment}>+1</button> </div> ); }
57. 什么是React的StrictMode?它有什么作用?
StrictMode 是一个用于检测潜在问题的开发工具,仅在开发环境生效:
检测内容:
-
不推荐的API使用:
- 废弃的生命周期方法(如
componentWillReceiveProps) - 不安全的
findDOMNode使用 - 过时的context API
- 废弃的生命周期方法(如
-
副作用验证:
- 检查
useEffect是否正确清除副作用 - 检测意外的副作用(通过两次调用函数组件)
- 检查
-
安全检查:
- 确保状态初始化纯净
- 验证
getDerivedStateFromProps的使用
启用方式:
jsx
<React.StrictMode>
<App />
</React.StrictMode>
58. 如何在React中优化大型列表渲染性能?
列表性能优化:
-
虚拟列表(Virtualization):
jsximport { FixedSizeList } from'react-window'; const Row = ({ index, style }) => { return ( <div style={style}> Row {index}: {data[index]} </div> ); }; const List = () => ( <FixedSizeList height={600} width={800} itemSize={35} itemCount={data.length} > {Row} </FixedSizeList> ); -
使用memo防止不必要的重渲染:
jsxconst MemoizedItem = memo(({ item }) => ( <div>{item.name}</div> )); // 列表渲染 {items.map((item) => ( <MemoizedItem key={item.id} item={item} /> ))}
59. 如何在React中实现暗黑模式(Dark Mode)?
暗黑模式实现:
-
CSS变量 + Context API :
jsx// ThemeContext.js export const ThemeContext = React.createContext(); const ThemeProvider = ({ children }) => { const [theme, setTheme] = useState('light'); const toggleTheme = () => setTheme(theme === 'light' ? 'dark' : 'light'); return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> {children} </ThemeContext.Provider> ); }; // 全局样式 :root { --bg-color: #ffffff; --text-color: #000000; } .dark-mode { --bg-color: #1a1a1a; --text-color: #ffffff; } // 使用 <div className={theme === 'dark' ? 'dark-mode' : ''}> <p style={{ color: 'var(--text-color)' }}>Hello World</p> </div>
60. 如何在React中实现WebSocket通信?
WebSocket实现:
-
使用useState和useEffect:
jsxconst [messages, setMessages] = useState([]); const [socket, setSocket] = useState(null); useEffect(() => { const ws = new WebSocket('ws://localhost:8080'); setSocket(ws); ws.onmessage = (event) => { setMessages((prev) => [...prev, JSON.parse(event.data)]); }; return () => { ws.close(); }; }, []); const sendMessage = (message) => { socket?.send(JSON.stringify(message)); }; -
自定义Hook封装WebSocket逻辑:
jsxfunction useWebSocket(url) { const [messages, setMessages] = useState([]); const socketRef = useRef(null); useEffect(() => { socketRef.current = new WebSocket(url); socketRef.current.onmessage = (event) => { setMessages((prev) => [...prev, JSON.parse(event.data)]); }; return () => { socketRef.current.close(); }; }, [url]); const sendMessage = (message) => { socketRef.current.send(JSON.stringify(message)); }; return { messages, sendMessage }; } // 使用 function Chat() { const { messages, sendMessage } = useWebSocket('ws://localhost:8080'); return ( <div> {messages.map((msg) => ( <div key={msg.id}>{msg.text}</div> ))} <button onClick={() => sendMessage({ text: 'Hello' })}>Send</button> </div> ); }