Appearance
概述
React 是一个用于构建用户界面的 JavaScript 库。它允许开发人员创建可重用的 UI 组件,这些组件可以独立于其他组件进行渲染和更新。
React 的主要特点是声明式编程模型,其中开发者使用 JSX(JavaScript XML)语法来描述 UI 组件的结构和行为。这种声明性编程模型使得代码更加简洁、易于维护和扩展。
React 还提供了许多有用的功能和工具,如虚拟 DOM、组件生命周期钩子、状态管理和路由等。这些功能和工具帮助开发者更高效地构建复杂的用户界面应用程序。
常用Hooks
- useState 用途:用于在函数组件中添加状态。
示例:
jsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}
export default Counter;
- useEffect 用途:用于执行副作用操作,如数据获取、订阅或手动更改 DOM。
示例:
jsx
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
return () => {
// 清理副作用
document.title = 'React App';
};
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Example;
- useContext 用途:用于访问 React Context。
示例:
jsx
import React, { createContext, useContext, useState } from 'react';
const ThemeContext = createContext('light');
function App() {
const [theme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={theme}>
<div>
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
<ChildComponent />
</div>
</ThemeContext.Provider>
);
}
function ChildComponent() {
const theme = useContext(ThemeContext);
return <div style={{ backgroundColor: theme === 'dark' ? 'black' : 'white' }}>Child Component</div>;
}
export default App;
- useReducer 用途:用于替代 useState 来管理更复杂的组件状态。
示例:
jsx
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + 1 };
case 'decrement':
return { ...state, 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' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
export default Counter;
- useCallback
性能优化,防止不必要渲染
用途:用于创建带有稳定引用的回调函数。
示例:
jsx
import React, { useState, useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const callback = useCallback(() => {
console.log('Callback called');
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ChildComponent callback={callback} />
</div>
);
}
function ChildComponent({ callback }) {
return (
<div>
<button onClick={callback}>Call Callback</button>
</div>
);
}
export default ParentComponent;
- useMemo
性能优化,防止不必要渲染
用途:useMemo用于避免不必要的重新计算。它会 memoize(缓存)一个值,并仅当其依赖项发生变化时才重新计算这个值。 示例:
jsx
import React, { useState, useMemo } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const heavyComputation = useMemo(() => {
console.log('Heavy computation');
return Array.from({ length: 1000000 }, () => Math.random());
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ChildComponent data={heavyComputation} />
</div>
);
}
function ChildComponent({ data }) {
return (
<div>
<p>Data Length: {data.length}</p>
</div>
);
}
export default ParentComponent;
- useRef 用途:用于获取 DOM 元素或组件的引用。 示例:
jsx
import React, { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// 当按钮被点击时,使文本框获得焦点
inputEl.current.focus();
};
return (
<div>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
}
export default TextInputWithFocusButton;
- useImperativeHandle
用途:用于自定义暴露给父组件的 ref 对象。 示例:
jsx
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
function CustomTextInput(props, ref) {
const inputEl = useRef(null);
useImperativeHandle(ref, () => ({ // 把子组件方法暴露给父组件,类似vue3 defineExpose
focus: () => {
inputEl.current.focus();
}
}));
return (
<input ref={inputEl} type="text" />
);
}
// forwardRef 允许我们创建一个组件,该组件可以暴露一个 ref 对象,父组件通过该ref获取子组件实例
const CustomTextInputWithRef = forwardRef(CustomTextInput);
function ParentComponent() {
const customTextInput = useRef(null);
const onButtonClick = () => {
customTextInput.current.focus();
};
return (
<div>
<CustomTextInputWithRef ref={customTextInput} />
<button onClick={onButtonClick}>Focus the input</button>
</div>
);
}
export default ParentComponent;
- useLayoutEffect 用途:在组件渲染后,在浏览器绘制之前执行。 示例:
jsx
import React, { useState, useLayoutEffect } from 'react';
function Example() {
const [width, setWidth] = useState(window.innerWidth);
useLayoutEffect(() => {
function handleResize() {
setWidth(window.innerWidth);
}
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<div>
<p>Window width: {width}px</p>
</div>
);
}
export default Example;
react 常用api react.memo react.memo 是一个高阶组件(Higher-Order Component, HOC),用于优化函数组件的性能。它可以避免不必要的重新渲染,提高应用的性能。下面详细介绍 react.memo 的用法和应用场景。
基本用法 react.memo 接受一个函数组件,并返回一个新的组件。这个新组件会在其 props 发生变化时才会重新渲染。
示例 假设有一个简单的函数组件,我们希望只有当 props 发生变化时才重新渲染。
jsx
import React, { memo } from 'react';
const Greeting = memo(({ name }) => {
console.log('Rendering Greeting');
return <h1>Hello, {name}!</h1>;
});
function App() {
const [name, setName] = React.useState('World');
return (
<div>
<Greeting name={name} />
<button onClick={() => setName('Ali')}>Change Name</button>
</div>
);
}
export default App;
在这个例子中,Greeting 组件被 memo 包装后,只有当 name 发生变化时才会重新渲染。
- 自定义比较函数 默认情况下,react.memo 使用浅层比较(shallow comparison)来检查 props 是否发生变化。如果你需要更精细的比较逻辑,可以传递一个自定义的比较函数作为第二个参数。
jsx
import React, { memo } from 'react';
const Greeting = memo(
({ name }) => {
console.log('Rendering Greeting');
return <h1>Hello, {name}!</h1>;
},
(prevProps, nextProps) => {
// 自定义比较逻辑
return prevProps.name === nextProps.name;
}
);
function App() {
const [name, setName] = React.useState('World');
return (
<div>
<Greeting name={name} />
<button onClick={() => setName('Ali')}>Change Name</button>
</div>
);
}
export default App;
注意:memo底层通过Object.is
判断props是否发生变化,当传递引用类型的props,父组件更新时都会重新创建,所以子组件每次都会更新,在父组件配合useMemo和useCallback创建引用型props参数可以避免这个问题