MST

星途 面试题库

面试题:使用 React Hooks 进行复杂状态管理及性能优化

假设你有一个包含多个子组件的 React 应用,这些子组件之间存在复杂的状态交互。请描述如何使用 React Hooks(如 useReducer 和 useContext)来有效地管理这些状态,并通过合适的手段(如 memo 或 useCallback)进行性能优化。给出关键代码示例及思路。
28.9万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

1. 使用 useReducer 管理状态

  • 思路useReduceruseState 的替代方案,适用于状态逻辑较复杂且包含多个子值,或者下一个状态依赖于之前的状态等场景。它接收一个 reducer 函数和初始状态,返回当前状态和一个 dispatch 方法,用于更新状态。
  • 关键代码示例
import React, { useReducer } from'react';

// reducer 函数,处理状态更新逻辑
const reducer = (state, action) => {
    switch (action.type) {
        case 'UPDATE_VALUE':
            return {
               ...state,
                value: action.payload
            };
        default:
            return state;
    }
};

const ParentComponent = () => {
    const initialState = {
        value: 0
    };
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <div>
            <p>Value: {state.value}</p>
            <button onClick={() => dispatch({ type: 'UPDATE_VALUE', payload: state.value + 1 })}>Increment</button>
        </div>
    );
};

export default ParentComponent;

2. 使用 useContext 共享状态

  • 思路useContext 用于在组件树中共享数据,避免通过多层组件传递 props(即 “props 钻取”)。它接收一个 Context 对象并返回该 Context 的当前值。
  • 关键代码示例
import React, { createContext, useContext, useReducer } from'react';

// 创建 Context
const MyContext = createContext();

// reducer 函数
const reducer = (state, action) => {
    switch (action.type) {
        case 'UPDATE_VALUE':
            return {
               ...state,
                value: action.payload
            };
        default:
            return state;
    }
};

const ParentComponent = () => {
    const initialState = {
        value: 0
    };
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <MyContext.Provider value={{ state, dispatch }}>
            <ChildComponent />
        </MyContext.Provider>
    );
};

const ChildComponent = () => {
    const { state, dispatch } = useContext(MyContext);

    return (
        <div>
            <p>Value from context: {state.value}</p>
            <button onClick={() => dispatch({ type: 'UPDATE_VALUE', payload: state.value + 1 })}>Increment from child</button>
        </div>
    );
};

export default ParentComponent;

3. 使用 memo 进行性能优化

  • 思路memo 是一个高阶组件,它可以对函数组件进行记忆化。它会在组件接收到新的 props 时,对比前后的 props,如果没有变化,则不会重新渲染该组件,从而提高性能。
  • 关键代码示例
import React, { createContext, useContext, useReducer } from'react';

const MyContext = createContext();

const reducer = (state, action) => {
    switch (action.type) {
        case 'UPDATE_VALUE':
            return {
               ...state,
                value: action.payload
            };
        default:
            return state;
    }
};

const ParentComponent = () => {
    const initialState = {
        value: 0
    };
    const [state, dispatch] = useReducer(reducer, initialState);

    return (
        <MyContext.Provider value={{ state, dispatch }}>
            <MemoizedChildComponent />
        </MyContext.Provider>
    );
};

const MemoizedChildComponent = React.memo(() => {
    const { state, dispatch } = useContext(MyContext);

    return (
        <div>
            <p>Value from context: {state.value}</p>
            <button onClick={() => dispatch({ type: 'UPDATE_VALUE', payload: state.value + 1 })}>Increment from child</button>
        </div>
    );
});

export default ParentComponent;

4. 使用 useCallback 进行性能优化

  • 思路useCallback 用于返回一个记忆化的回调函数。它接收一个回调函数和一个依赖数组,只有当依赖数组中的值发生变化时,才会返回新的回调函数。在子组件依赖于父组件传递的回调函数时,使用 useCallback 可以避免不必要的重新渲染。
  • 关键代码示例
import React, { createContext, useContext, useReducer, useCallback } from'react';

const MyContext = createContext();

const reducer = (state, action) => {
    switch (action.type) {
        case 'UPDATE_VALUE':
            return {
               ...state,
                value: action.payload
            };
        default:
            return state;
    }
};

const ParentComponent = () => {
    const initialState = {
        value: 0
    };
    const [state, dispatch] = useReducer(reducer, initialState);

    const increment = useCallback(() => {
        dispatch({ type: 'UPDATE_VALUE', payload: state.value + 1 });
    }, [dispatch, state.value]);

    return (
        <MyContext.Provider value={{ state, increment }}>
            <ChildComponent />
        </MyContext.Provider>
    );
};

const ChildComponent = () => {
    const { state, increment } = useContext(MyContext);

    return (
        <div>
            <p>Value from context: {state.value}</p>
            <button onClick={increment}>Increment from child</button>
        </div>
    );
};

export default ParentComponent;