React 基础与进阶
约 4158 字大约 14 分钟
React 基础与进阶
React核心概念 🟢
1. JSX语法
JSX是JavaScript的语法扩展,允许在JavaScript中编写类似HTML的代码。
// JSX基础语法
const element = <h1>Hello, {name}</h1>;
// 条件渲染
const element = (
<div>
{isLoggedIn ? (
<UserGreeting />
) : (
<GuestGreeting />
)}
</div>
);
// 列表渲染
const listItems = items.map(item => (
<li key={item.id}>{item.text}</li>
));
// 属性传递
const element = <img src={user.avatarUrl} alt={user.name} />;
// Fragment使用
const element = (
<>
<ChildA />
<ChildB />
</>
);
2. 组件基础
函数组件
// 基础函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 箭头函数组件
const Welcome = ({ name }) => {
return <h1>Hello, {name}</h1>;
};
// 带默认props
Welcome.defaultProps = {
name: 'Guest'
};
// 使用PropTypes进行类型检查
Welcome.propTypes = {
name: PropTypes.string.isRequired
};
类组件
class Welcome extends React.Component {
static defaultProps = {
name: 'Guest'
};
static propTypes = {
name: PropTypes.string.isRequired
};
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
React生命周期 🟡
1. 类组件生命周期
class LifecycleComponent extends React.Component {
// 挂载阶段
constructor(props) {
super(props);
this.state = { count: 0 };
}
static getDerivedStateFromProps(props, state) {
// 返回新状态或null
return null;
}
componentDidMount() {
// 组件挂载后执行
// 适合做异步请求、订阅等
}
// 更新阶段
shouldComponentUpdate(nextProps, nextState) {
// 返回true或false决定是否更新
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 在更新之前获取一些信息
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 组件更新后执行
}
// 卸载阶段
componentWillUnmount() {
// 清理工作,如取消订阅等
}
// 错误处理
static getDerivedStateFromError(error) {
// 返回新状态
return { hasError: true };
}
componentDidCatch(error, info) {
// 错误日志记录
}
render() {
return <div>{this.state.count}</div>;
}
}
2. 函数组件生命周期(Hooks)
function FunctionalComponent() {
// 相当于constructor和componentDidMount的组合
useEffect(() => {
// 组件挂载后执行
return () => {
// 组件卸载前执行(清理工作)
};
}, []); // 空依赖数组
// 相当于componentDidUpdate
useEffect(() => {
// 当依赖项改变时执行
}, [dependency]);
// 相当于componentWillUnmount
useEffect(() => {
return () => {
// 清理工作
};
});
return <div>Functional Component</div>;
}
React Hooks详解 🔴
1. 基础Hooks
useState
function Counter() {
const [count, setCount] = useState(0);
// 函数式更新
const increment = () => {
setCount(prevCount => prevCount + 1);
};
// 对象状态
const [state, setState] = useState({ count: 0, name: 'test' });
const updateState = () => {
setState(prev => ({
...prev,
count: prev.count + 1
}));
};
return <button onClick={increment}>{count}</button>;
}
useEffect
function DataFetcher() {
const [data, setData] = useState(null);
// 数据获取
useEffect(() => {
let mounted = true;
async function fetchData() {
try {
const response = await fetch('api/data');
const result = await response.json();
if (mounted) {
setData(result);
}
} catch (error) {
console.error('Error:', error);
}
}
fetchData();
return () => {
mounted = false;
};
}, []);
return <div>{/* 渲染数据 */}</div>;
}
useContext
// 创建Context
const ThemeContext = React.createContext('light');
// 提供Context
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
// 使用Context
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
2. 额外的Hooks
useReducer
// 定义reducer
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
return state;
}
};
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}
useCallback & useMemo
function SearchResults() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
// 缓存函数
const handleSearch = useCallback((searchQuery) => {
// 搜索逻辑
}, []); // 空依赖数组
// 缓存计算结果
const filteredResults = useMemo(() => {
return results.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
);
}, [results, query]);
return (
<div>
<input value={query} onChange={e => setQuery(e.target.value)} />
<ResultsList results={filteredResults} onItemClick={handleSearch} />
</div>
);
}
useRef
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
// 保存前一个值
const prevCountRef = useRef();
useEffect(() => {
prevCountRef.current = count;
});
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
3. 自定义Hooks
// 自定义Hook:处理表单
function useForm(initialValues = {}) {
const [values, setValues] = useState(initialValues);
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setValues(prev => ({
...prev,
[name]: value
}));
}, []);
const reset = useCallback(() => {
setValues(initialValues);
}, [initialValues]);
return { values, handleChange, reset };
}
// 使用自定义Hook
function LoginForm() {
const { values, handleChange, reset } = useForm({
username: '',
password: ''
});
const handleSubmit = (e) => {
e.preventDefault();
// 处理提交
reset();
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={values.username}
onChange={handleChange}
/>
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
/>
<button type="submit">Login</button>
</form>
);
}
状态管理 🔴
1. Context + useReducer
// 创建Context
const TodoContext = React.createContext();
// 定义reducer
const todoReducer = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload];
case 'REMOVE_TODO':
return state.filter(todo => todo.id !== action.payload);
default:
return state;
}
};
// Context Provider
function TodoProvider({ children }) {
const [todos, dispatch] = useReducer(todoReducer, []);
return (
<TodoContext.Provider value={{ todos, dispatch }}>
{children}
</TodoContext.Provider>
);
}
// 使用Context
function TodoList() {
const { todos, dispatch } = useContext(TodoContext);
const handleRemove = (id) => {
dispatch({ type: 'REMOVE_TODO', payload: id });
};
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<button onClick={() => handleRemove(todo.id)}>删除</button>
</li>
))}
</ul>
);
}
2. Redux集成
// Action Types
const ADD_TODO = 'ADD_TODO';
const REMOVE_TODO = 'REMOVE_TODO';
// Action Creators
const addTodo = (text) => ({
type: ADD_TODO,
payload: { id: Date.now(), text }
});
// Reducer
const todoReducer = (state = [], action) => {
switch (action.type) {
case ADD_TODO:
return [...state, action.payload];
case REMOVE_TODO:
return state.filter(todo => todo.id !== action.payload);
default:
return state;
}
};
// Redux Hooks使用
function TodoList() {
const todos = useSelector(state => state.todos);
const dispatch = useDispatch();
const handleAdd = (text) => {
dispatch(addTodo(text));
};
return (
// 渲染列表
);
}
性能优化 🔴
1. React.memo
// 基础使用
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.name}</div>;
});
// 自定义比较函数
const MyComponent = React.memo(function MyComponent(props) {
return <div>{props.name}</div>;
}, (prevProps, nextProps) => {
return prevProps.name === nextProps.name;
});
2. 虚拟列表
function VirtualList({ items, height, itemHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const visibleItems = useMemo(() => {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(
startIndex + Math.ceil(height / itemHeight),
items.length
);
return items.slice(startIndex, endIndex).map((item, index) => ({
...item,
index: startIndex + index
}));
}, [scrollTop, items, height, itemHeight]);
const handleScroll = useCallback((e) => {
setScrollTop(e.target.scrollTop);
}, []);
return (
<div
style={{ height, overflow: 'auto' }}
onScroll={handleScroll}
>
<div style={{ height: items.length * itemHeight }}>
{visibleItems.map(item => (
<div
key={item.id}
style={{
position: 'absolute',
top: item.index * itemHeight,
height: itemHeight
}}
>
{item.content}
</div>
))}
</div>
</div>
);
}
3. 代码分割
// 路由级别的代码分割
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
);
}
// 组件级别的代码分割
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function MyComponent() {
const [showHeavy, setShowHeavy] = useState(false);
return (
<div>
<button onClick={() => setShowHeavy(true)}>
Load Heavy Component
</button>
{showHeavy && (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
)}
</div>
);
}
错误处理 🟡
1. 错误边界
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// 记录错误日志
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
// 使用错误边界
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
2. 异步错���处理
function AsyncComponent() {
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const response = await fetch('api/data');
const result = await response.json();
setData(result);
} catch (err) {
setError(err);
// 错误上报
reportError(err);
}
}
fetchData();
}, []);
if (error) {
return <div>Error: {error.message}</div>;
}
if (!data) {
return <div>Loading...</div>;
}
return <div>{/* 渲染数据 */}</div>;
}
测试 🟡
1. 单元测试
// 使用Jest和React Testing Library
import { render, fireEvent, waitFor } from '@testing-library/react';
import Counter from './Counter';
describe('Counter Component', () => {
test('renders initial count', () => {
const { getByText } = render(<Counter />);
expect(getByText('0')).toBeInTheDocument();
});
test('increments count when button is clicked', () => {
const { getByText } = render(<Counter />);
fireEvent.click(getByText('+'));
expect(getByText('1')).toBeInTheDocument();
});
test('async data fetching', async () => {
const { getByText } = render(<DataComponent />);
await waitFor(() => {
expect(getByText('Data loaded')).toBeInTheDocument();
});
});
});
2. 集成测试
describe('App Integration', () => {
test('full app rendering/navigating', () => {
const { getByText, getByTestId } = render(
<MemoryRouter initialEntries={['/']}>
<App />
</MemoryRouter>
);
// 验证页面内容
expect(getByText('Home')).toBeInTheDocument();
// 触发导航
fireEvent.click(getByText('About'));
// 验证导航结果
expect(getByText('About Page')).toBeInTheDocument();
});
test('landing on a bad page shows 404', () => {
const { getByText } = render(
<MemoryRouter initialEntries={['/bad-route']}>
<App />
</MemoryRouter>
);
expect(getByText('404')).toBeInTheDocument();
});
});
React高级特性 🔴
1. Fiber架构
Fiber原理
- Fiber是React 16引入的新协调引擎
- 支持���务优先级、中断和恢复
- 实现增量渲染
// Fiber节点结构
interface FiberNode {
// 静态数据结构
tag: WorkTag; // 标记不同组件类型
key: null | string; // key属性
elementType: any; // 元素类型
type: any; // 组件类型
stateNode: any; // 实际DOM节点
// 用于连接其他Fiber节点形成Fiber树
return: Fiber | null; // 父节点
child: Fiber | null; // 子节点
sibling: Fiber | null; // 兄弟节点
index: number; // 索引
// 用于状态更新
pendingProps: any; // 新的props
memoizedProps: any; // 旧的props
updateQueue: UpdateQueue<any> | null; // 更新队列
memoizedState: any; // 旧的state
// 副作用
flags: Flags; // 副作用标记
subtreeFlags: Flags; // 子树副作用标记
deletions: Array<Fiber> | null; // 需要删除的节点
// 调度优先级
lanes: Lanes; // 优先级
childLanes: Lanes; // 子节点优先级
}
Fiber更新过程
- 调度阶段(Scheduler)
- 协调阶段(Reconciler)
- 提交阶段(Commit)
2. Concurrent Mode
// 开启并发模式
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
// 使用Suspense和并发特性
function App() {
return (
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
);
}
// 并发更新
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
function handleClick() {
startTransition(() => {
setCount(c => c + 1);
});
}
3. 服务端渲染(SSR)
// 服务端代码
import ReactDOMServer from 'react-dom/server';
app.get('/', (req, res) => {
const html = ReactDOMServer.renderToString(<App />);
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR App</title>
</head>
<body>
<div id="root">${html}</div>
<script src="/client.js"></script>
</body>
</html>
`);
});
// 客户端代码
import { hydrateRoot } from 'react-dom/client';
hydrateRoot(
document.getElementById('root'),
<App />
);
4. React性能优化
1. 使用React.memo深入优化
// 自定义比较函数
const areEqual = (prevProps, nextProps) => {
return (
prevProps.id === nextProps.id &&
prevProps.name === nextProps.name &&
prevProps.data.every((item, index) =>
item.id === nextProps.data[index].id
)
);
};
const MemoizedComponent = React.memo(function MyComponent(props) {
return (
// 组件内容
);
}, areEqual);
// 使用useMemo优化计算
function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
return data.map(item => ({
...item,
processed: expensiveOperation(item)
}));
}, [data]);
return (
// 渲染处理后的数据
);
}
2. 虚拟列表优化
function VirtualList({ items, height, itemHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef();
const visibleItems = useMemo(() => {
const start = Math.floor(scrollTop / itemHeight);
const end = Math.min(
start + Math.ceil(height / itemHeight),
items.length
);
return items.slice(start, end).map((item, index) => ({
...item,
index: start + index
}));
}, [scrollTop, items, height, itemHeight]);
const handleScroll = useCallback((e) => {
requestAnimationFrame(() => {
setScrollTop(e.target.scrollTop);
});
}, []);
const totalHeight = items.length * itemHeight;
const offsetY = Math.floor(scrollTop / itemHeight) * itemHeight;
return (
<div
ref={containerRef}
style={{ height, overflow: 'auto' }}
onScroll={handleScroll}
>
<div style={{ height: totalHeight }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
{visibleItems.map(item => (
<div
key={item.id}
style={{ height: itemHeight }}
>
{item.content}
</div>
))}
</div>
</div>
</div>
);
}
3. 状态管理优化
// 使用Context优化props drilling
const StateContext = React.createContext();
const DispatchContext = React.createContext();
function StateProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
);
}
// 自定义Hook封装状态逻辑
function useCustomState() {
const state = useContext(StateContext);
const dispatch = useContext(DispatchContext);
const updateState = useCallback((action) => {
dispatch(action);
}, [dispatch]);
return [state, updateState];
}
5. React Hooks进阶
1. 自定义Hooks最佳实践
// 封装异步逻辑
function useAsync(asyncFunction, immediate = true) {
const [status, setStatus] = useState('idle');
const [value, setValue] = useState(null);
const [error, setError] = useState(null);
const execute = useCallback(async () => {
setStatus('pending');
setValue(null);
setError(null);
try {
const response = await asyncFunction();
setValue(response);
setStatus('success');
} catch (error) {
setError(error);
setStatus('error');
}
}, [asyncFunction]);
useEffect(() => {
if (immediate) {
execute();
}
}, [execute, immediate]);
return { execute, status, value, error };
}
// 封装表单逻辑
function useForm(initialValues = {}) {
const [values, setValues] = useState(initialValues);
const [errors, setErrors] = useState({});
const [touched, setTouched] = useState({});
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setValues(prev => ({
...prev,
[name]: value
}));
}, []);
const handleBlur = useCallback((e) => {
const { name } = e.target;
setTouched(prev => ({
...prev,
[name]: true
}));
}, []);
const validate = useCallback((validationSchema) => {
try {
validationSchema.validateSync(values, { abortEarly: false });
setErrors({});
return true;
} catch (validationError) {
const errors = {};
validationError.inner.forEach(error => {
errors[error.path] = error.message;
});
setErrors(errors);
return false;
}
}, [values]);
return {
values,
errors,
touched,
handleChange,
handleBlur,
validate
};
}
2. Hook规则和原理
// Hook规则示例
function Counter() {
// 1. 只在最顶层使用Hook
const [count, setCount] = useState(0);
// 2. 只在React函数中调用Hook
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
// 3. 自定义Hook必须以use开头
const value = useCustomHook();
if (count > 0) {
// 错误:条件语句中使用Hook
// const [error, setError] = useState(null);
}
return (
// JSX
);
}
// Hook原理实现示例
const MyReact = (function() {
let hooks = [];
let currentHook = 0;
return {
render(Component) {
currentHook = 0;
const app = Component();
return app;
},
useState(initialValue) {
hooks[currentHook] = hooks[currentHook] || initialValue;
const hookIndex = currentHook;
const setState = newValue => {
hooks[hookIndex] = newValue;
};
return [hooks[currentHook++], setState];
},
useEffect(callback, deps) {
const hasNoDeps = !deps;
const hook = hooks[currentHook];
const hasDepsChanged = hook
? !deps.every((dep, i) => dep === hook.deps[i])
: true;
if (hasNoDeps || hasDepsChanged) {
callback();
hooks[currentHook] = { deps };
}
currentHook++;
}
};
})();
6. React设计模式
1. 复合组件模式
// 复合组件示例
const Select = {
Root: ({ children, ...props }) => (
<div className="select" {...props}>
{children}
</div>
),
Trigger: ({ children }) => (
<div className="select-trigger">
{children}
</div>
),
Options: ({ children }) => (
<div className="select-options">
{children}
</div>
),
Option: ({ children, ...props }) => (
<div className="select-option" {...props}>
{children}
</div>
)
};
// 使用复合组件
function CustomSelect() {
return (
<Select.Root>
<Select.Trigger>
选择选项
</Select.Trigger>
<Select.Options>
<Select.Option>选项1</Select.Option>
<Select.Option>选项2</Select.Option>
</Select.Options>
</Select.Root>
);
}
2. 控制反转
// 控制反转示例
function DataFetcher({ children, url }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetchData(url)
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, [url]);
return children({ data, loading, error });
}
// 使用示例
function UserList() {
return (
<DataFetcher url="/api/users">
{({ data, loading, error }) => {
if (loading) return <Loading />;
if (error) return <Error error={error} />;
return <UserTable data={data} />;
}}
</DataFetcher>
);
}
3. 高阶组件(HOC)
// 高阶组件示例
function withAuth(WrappedComponent) {
return function WithAuthComponent(props) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [loading, setLoading] = useState(true);
useEffect(() => {
checkAuth()
.then(auth => {
setIsAuthenticated(auth);
setLoading(false);
});
}, []);
if (loading) {
return <Loading />;
}
if (!isAuthenticated) {
return <Redirect to="/login" />;
}
return <WrappedComponent {...props} />;
};
}
// 使用HOC
const ProtectedComponent = withAuth(UserDashboard);
React高级模式和最佳实践 🔴
1. Render Props模式
// 基础实现
class Mouse extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
// 使用示例
<Mouse render={({ x, y }) => (
<h1>鼠标位置:{x}, {y}</h1>
)}/>
// 高级用法 - 结合HOC
function withMouse(WrappedComponent) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<WrappedComponent {...this.props} mouse={mouse} />
)}/>
);
}
};
}
2. Compound Components(复合组件)
// 基础实现
const RadioGroup = React.createContext();
function RadioGroupComponent({ children, value, onChange }) {
return (
<RadioGroup.Provider value={{ value, onChange }}>
{children}
</RadioGroup.Provider>
);
}
function RadioButton({ value, children }) {
const context = React.useContext(RadioGroup);
const checked = context.value === value;
return (
<label>
<input
type="radio"
value={value}
checked={checked}
onChange={() => context.onChange(value)}
/>
{children}
</label>
);
}
// 使用示例
function App() {
const [selected, setSelected] = useState('');
return (
<RadioGroupComponent value={selected} onChange={setSelected}>
<RadioButton value="option1">选项1</RadioButton>
<RadioButton value="option2">选项2</RadioButton>
</RadioGroupComponent>
);
}
3. 状态机模式
// 使用状态机管理复杂UI状态
const STATES = {
IDLE: 'IDLE',
LOADING: 'LOADING',
SUCCESS: 'SUCCESS',
ERROR: 'ERROR'
};
function reducer(state, action) {
switch (action.type) {
case 'FETCH':
return { ...state, status: STATES.LOADING };
case 'SUCCESS':
return {
status: STATES.SUCCESS,
data: action.payload,
error: null
};
case 'ERROR':
return {
status: STATES.ERROR,
error: action.payload,
data: null
};
default:
return state;
}
}
function DataFetcher({ url, children }) {
const [state, dispatch] = useReducer(reducer, {
status: STATES.IDLE,
data: null,
error: null
});
useEffect(() => {
async function fetchData() {
dispatch({ type: 'FETCH' });
try {
const response = await fetch(url);
const data = await response.json();
dispatch({ type: 'SUCCESS', payload: data });
} catch (error) {
dispatch({ type: 'ERROR', payload: error });
}
}
fetchData();
}, [url]);
return children(state);
}
// 使用示例
<DataFetcher url="/api/data">
{({ status, data, error }) => {
switch (status) {
case STATES.LOADING:
return <Loading />;
case STATES.ERROR:
return <Error error={error} />;
case STATES.SUCCESS:
return <DataDisplay data={data} />;
default:
return null;
}
}}
</DataFetcher>
4. 可控组件模式
// 完全可控的表单组件
function ControlledForm({ onSubmit }) {
const [values, setValues] = useState({});
const [errors, setErrors] = useState({});
const [touched, setTouched] = useState({});
const handleChange = useCallback((e) => {
const { name, value } = e.target;
setValues(prev => ({
...prev,
[name]: value
}));
}, []);
const handleBlur = useCallback((e) => {
const { name } = e.target;
setTouched(prev => ({
...prev,
[name]: true
}));
}, []);
const validate = useCallback(() => {
const newErrors = {};
// 验证逻辑
return newErrors;
}, [values]);
const handleSubmit = useCallback((e) => {
e.preventDefault();
const newErrors = validate();
if (Object.keys(newErrors).length === 0) {
onSubmit(values);
} else {
setErrors(newErrors);
}
}, [values, validate, onSubmit]);
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={values.email || ''}
onChange={handleChange}
onBlur={handleBlur}
/>
{touched.email && errors.email && (
<span className="error">{errors.email}</span>
)}
{/* 其他表单字段 */}
</form>
);
}
5. 性能优化模式
// 使用React.memo的高级用法
const MemoizedComponent = React.memo(function Component(props) {
return <div>{props.value}</div>;
}, (prevProps, nextProps) => {
// 自定义比较逻辑
return prevProps.value === nextProps.value;
});
// 使用useCallback优化事件处理器
function OptimizedComponent({ onItemClick }) {
const [items, setItems] = useState([]);
const handleClick = useCallback((id) => {
onItemClick(id);
}, [onItemClick]);
return (
<ul>
{items.map(item => (
<li key={item.id} onClick={() => handleClick(item.id)}>
{item.name}
</li>
))}
</ul>
);
}
// 使用useMemo优化计算
function ExpensiveList({ items, filter }) {
const filteredItems = useMemo(() => {
return items.filter(item => {
console.log('Filtering items...');
return item.name.includes(filter);
});
}, [items, filter]);
return (
<ul>
{filteredItems.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
React高级面试题 🔴
1. React Fiber相关
Q1: 什么是React Fiber?它解决了什么问题? A1:
- Fiber是React 16中引入的新协调引擎
- 主要解决的问题:
- 大型应用中的性能问题
- 更好的错误处理
- 支持异步渲染
- 支持任务优先级
- 工作原理:
// Fiber节点结构
interface FiberNode {
// 静态数据
type: any;
key: null | string;
elementType: any;
// 链接其他Fiber节点
return: Fiber | null;
child: Fiber | null;
sibling: Fiber | null;
// 动态工作
pendingProps: any;
memoizedProps: any;
updateQueue: UpdateQueue<any> | null;
memoizedState: any;
// 副作用
flags: Flags;
subtreeFlags: Flags;
// 调度优先级
lanes: Lanes;
childLanes: Lanes;
}
Q2: React的调度过程是怎样的? A2:
调度过程分为几个阶段:
- Schedule(调度):确定更新的优先级
- Reconciliation(协调):构建Fiber树
- Commit(提交):将更新应用到DOM
示例说明:
// 调度示例
function updateComponent(fiber) {
// 1. 设置优先级
const updateLane = getCurrentPriorityLevel();
// 2. 创建更新
const update = createUpdate(updateLane);
// 3. 加入更新队列
enqueueUpdate(fiber, update);
// 4. 调度更新
scheduleUpdateOnFiber(fiber);
}
// 协调过程
function reconcileChildren(current, workInProgress, nextChildren) {
if (current === null) {
// 首次渲染
workInProgress.child = mountChildFibers(
workInProgress,
null,
nextChildren
);
} else {
// 更新
workInProgress.child = reconcileChildFibers(
workInProgress,
current.child,
nextChildren
);
}
}
2. React Hooks深入
Q1: 如何实现一个自定义Hook?需要注意什么? A1:
- 实现示例:
// 自定义Hook - 处理API请求
function useAPI(url, options = {}) {
const [state, dispatch] = useReducer(reducer, {
data: null,
loading: false,
error: null
});
const [controller, setController] = useState(null);
useEffect(() => {
let mounted = true;
const abortController = new AbortController();
setController(abortController);
async function fetchData() {
dispatch({ type: 'REQUEST' });
try {
const response = await fetch(url, {
...options,
signal: abortController.signal
});
const data = await response.json();
if (mounted) {
dispatch({ type: 'SUCCESS', payload: data });
}
} catch (error) {
if (mounted && error.name !== 'AbortError') {
dispatch({ type: 'ERROR', payload: error });
}
}
}
fetchData();
return () => {
mounted = false;
abortController.abort();
};
}, [url]);
const refetch = useCallback(() => {
if (controller) {
controller.abort();
}
dispatch({ type: 'RESET' });
}, [controller]);
return { ...state, refetch };
}
// 使用示例
function UserProfile({ userId }) {
const { data, loading, error, refetch } = useAPI(
`/api/users/${userId}`
);
if (loading) return <Loading />;
if (error) return <Error error={error} />;
return (
<div>
<h1>{data.name}</h1>
<button onClick={refetch}>刷新</button>
</div>
);
}
- 注意事项:
- 命名必须以use开头
- 只能在函数组件或其他Hook中调用
- 保持一致的依赖项数组
- 考虑性能优化
- 处理清理工作
Q2: React Hooks的实现原理是什么? A2:
// 简化版Hook实现
let hooks = [];
let currentHook = 0;
function useState(initialState) {
hooks[currentHook] = hooks[currentHook] || initialState;
const hookIndex = currentHook;
const setState = (newState) => {
hooks[hookIndex] = newState;
render();
};
return [hooks[currentHook++], setState];
}
function useEffect(callback, deps) {
const hasNoDeps = !deps;
const hook = hooks[currentHook];
const hasDepsChanged = hook
? !deps.every((dep, i) => dep === hook.deps[i])
: true;
if (hasNoDeps || hasDepsChanged) {
callback();
hooks[currentHook] = { deps };
}
currentHook++;
}
// 渲染函数
function render() {
currentHook = 0;
ReactDOM.render(<App />, document.getElementById('root'));
}
3. React性能优化深入
Q1: React中的性能优化技巧有哪些? A1:
- 代码分割:
// 路由级别的代码分割
const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
function App() {
return (
<Suspense fallback={<Loading />}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
);
}
// 组件级别的代码分割
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function MyComponent() {
const [showHeavy, setShowHeavy] = useState(false);
return (
<div>
<button onClick={() => setShowHeavy(true)}>
加载重组件
</button>
{showHeavy && (
<Suspense fallback={<Loading />}>
<HeavyComponent />
</Suspense>
)}
</div>
);
}
- 虚拟列表:
function VirtualList({ items, height, itemHeight }) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef();
const visibleItems = useMemo(() => {
const start = Math.floor(scrollTop / itemHeight);
const end = Math.min(
start + Math.ceil(height / itemHeight),
items.length
);
return items.slice(start, end).map((item, index) => ({
...item,
index: start + index
}));
}, [scrollTop, items, height, itemHeight]);
const handleScroll = useCallback((e) => {
requestAnimationFrame(() => {
setScrollTop(e.target.scrollTop);
});
}, []);
const totalHeight = items.length * itemHeight;
const offsetY = Math.floor(scrollTop / itemHeight) * itemHeight;
return (
<div
ref={containerRef}
style={{ height, overflow: 'auto' }}
onScroll={handleScroll}
>
<div style={{ height: totalHeight }}>
<div style={{ transform: `translateY(${offsetY}px)` }}>
{visibleItems.map(item => (
<div
key={item.id}
style={{ height: itemHeight }}
>
{item.content}
</div>
))}
</div>
</div>
</div>
);
}
- 状态管理优化:
// 使用Context优化props drilling
const StateContext = React.createContext();
const DispatchContext = React.createContext();
function StateProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
);
}
// 自定义Hook封装状态逻辑
function useCustomState() {
const state = useContext(StateContext);
const dispatch = useContext(DispatchContext);
const updateState = useCallback((action) => {
dispatch(action);
}, [dispatch]);
return [state, updateState];
}