原文:https://www.frontendjoy.com/p/react-like-a-pro-10-things-i-regret-not-knowing-earlier
作者:Ndeye Fatou Diop
译者:ChatGPT 4 Turbo
如果你是一个被 React 搞得焦头烂额的初级开发者,你并不孤单。
当我刚开始时,我犯了很多错误——如果我一开始就知道这十件事,这些错误本可以避免。
让我帮你绕过这些弯路。
目录
- 1. 使用 children 属性大幅提升应用性能
- 2. 何时使用 Refs 而不是 State
- 3. 优先使用命名导出而不是默认导出
- 4. 尽可能避免使用 useEffect
- 5. 理解 React 的生命周期
- 6. 使用 ESLint 追踪低级错误
- 7. 使用 React DevTools 更智能地调试
- 8. 使用错误边界避免整体崩溃
- 9. 像专业人士一样组织代码
- 10. React 官网拥有你需要的一切
1. 使用 children
属性大幅提升应用性能
children
属性不仅仅用于传递嵌套元素。
它是一个强大的工具,具有以下优势:
- 避免属性钻取:直接将属性传递给子组件,而不是通过父组件路由。
- 编写可扩展代码:无需修改父组件即可修改子组件。
- 避免"慢速"组件不必要的重渲染(见下面的例子 👇)。
❌ 错误示范: 每当 Dashboard
渲染时(即每次当前时间更新时),MyVerySlowComponent
都会重新渲染。
function App() {
// 其他逻辑...
return <Dashboard />;
}
function Dashboard() {
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setCurrentTime(new Date());
}, 1_000);
return () => clearInterval(intervalId);
}, []);
return (
<>
<h1>{currentTime.toTimeString()}</h1>
<MyVerySlowComponent />
</>
);
}
💡 你可以在这里看到使用 React Developer Tool 的分析器展示的性能问题。
✅ 正确示范: MyVerySlowComponent
不会不必要地重新渲染。
function App() {
return (
<Dashboard>
<MyVerySlowComponent />
</Dashboard>
);
}
function Dashboard({ children }) {
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setCurrentTime(new Date());
}, 1_000);
return () => clearInterval(intervalId);
}, []);
return (
<>
<h1>{currentTime.toTimeString()}</h1>
{children}
</>
);
}
💡 你可以在这里看到优化后的效果。
2. 何时使用 Refs 而不是 State
Refs 非常适合那些不应触发重新渲染的值。
与其默认使用 state,不如先问问自己:“这个值改变时需要触发重新渲染吗?” 如果答案是否定的,就使用 ref。
它们非常适合跟踪可变值,如计时器、DOM 元素或在渲染之间保持但不影响 UI 的值。
❌ 错误示范:我们在 state 中存储 intervalId
。当 intervalId
状态改变时组件会重新渲染,即使 UI 保持不变。
function Timer() {
const [time, setTime] = useState(new Date());
const [intervalId, setIntervalId]= useState();
useEffect(() => {
const id = setInterval(() => {
setTime(new Date());
}, 1_000);
setIntervalId(id);
return () => clearInterval(id);
}, []);
const stopTimer = () => {
intervalId && clearInterval(intervalId);
};
return (
<>
<>当前时间:{time.toLocaleTimeString()} </>
<button onClick={stopTimer}>停止计时器</button>
</>
);
}
✅ 正确示范:我们将 intervalId
存储为 ref。这意味着我们不会有额外的状态触发重新渲染。
function Timer() {
const [time, setTime] = useState(new Date());
const intervalIdRef = useRef();
const intervalId = intervalIdRef.current;
useEffect(() => {
const id = setInterval(() => {
setTime(new Date());
}, 1_000);
intervalIdRef.current = id;
return () => clearInterval(id);
}, []);
const stopTimer = () => {
intervalId && clearInterval(intervalId);
};
return (
<>
<>当前时间:{time.toLocaleTimeString()} </>
<button onClick={stopTimer}>停止计时器</button>
</>
);
}
3. 优先使用命名导出而不是默认导出
命名导出使重构和调试更容易。
❌ 错误示范:重命名需要手动更新。
export default function Button() {}
// 之后...
import Button from './Button';
✅ 正确示范:重命名会自动发生。
export function Button() {}
// 之后...
import { Button } from './Button';
你可以在这篇文章中找到更多关于命名导入的论据 👉 101 个 React 技巧和窍门。
4. 尽可能避免使用 useEffect
我处理过的每一次应用崩溃背后都藏着 useEffect
😅。
说真的,尽量避免使用 useEffect
:
- 它很容易导致过度渲染、代码晦涩等问题。
- 它使代码流程更难追踪。
相反,考虑是否可以不使用它来实现相同的结果。
❌ 错误示范:在 useEffect
中调用 onToggled
。
function Toggle({ onToggled }) {
const [on, setOn] = React.useState(false);
const toggle = () => setOn(!on);
useEffect(() => {
onToggled(on);
}, [on]);
return (
<button onClick={toggle}>
{on ? 'on' : 'off'}
</button>
);
}
✅ 正确示范:在相关时机调用 onToggled
。
function Toggle({ onToggled }) {
const [on, setOn] = React.useState(false);
const handleToggle = () => {
const next = !on;
setOn(next);
onToggled(next);
};
return (
<button onClick={handleToggle}>
{on ? 'on' : 'off'}
</button>
);
}
你可以在这里找到更多避免使用 useEffect
的技巧 👉 你可能不需要 Effect。
5. 理解 React 的生命周期
了解生命周期阶段可以避免 bug 和性能问题:
- 挂载:组件首次渲染时。
- 更新:当某些状态改变并且 React 重新渲染时。
- 卸载:当组件从 DOM 中移除时。
6. 使用 ESLint 追踪低级错误
ESLint 可以帮你避免微妙的 bug,特别是在使用 hooks 时。
❌ 错误示范:useEffect
中缺少依赖项。
useEffect(() => {
console.log(data);
}, []); // 缺少依赖项!
✅ 正确示范:使用 ESLint 和插件如 eslint-plugin-react-hooks。
7. 使用 React DevTools 更智能地调试
React DevTools 对调试性能问题来说是黄金工具。使用"Profiler"标签来找出慢速组件。
❌ 错误示范:仅依赖 console.log
和计时器来猜测应用为什么慢。
✅ 正确示范:使用 Profiler 来:
- 找出过度渲染的组件。
- 通过火焰图定位昂贵的渲染。
💡 在这个很棒的指南中学习如何使用它。
8. 使用错误边界避免整体崩溃
默认情况下,如果你的应用在渲染过程中遇到错误,整个 UI 都会崩溃 💥。
为了防止这种情况,使用错误边界来:
- 即使发生错误,也能保持应用的部分功能。
- 显示用户友好的错误消息,并可选择跟踪错误。
💡 提示:你可以使用 react-error-boundary 包
9. 像专业人士一样组织代码
整洁的代码就是可维护的代码。
你可以遵循这些简单的提示:
- 将组件与相关资源(如样式、测试等)放在一起
- 保持文件小巧
- 将相关组件分组到文件夹中
❌ 错误示范:当你删除 Button.js
时,很容易忘记 Button.css
。
src/
components/
Button.js
Modal.js
styles/
Button.css
✅ 正确示范:我们将相关文件放在一起。
src/
components/
Button/
Button.js
Button.css
Button.test.js
10. React 官网拥有你需要的一切
不要忽视官方 React 文档。它们包含了大量示例、解释和最佳实践。
❌ 错误示范:无休止地搜索基本的 React 概念,最终落在过时的博客文章上。
✅ 正确示范:将官方文档加入书签,遇到问题时首先查阅它。
总结
掌握 React 需要时间。
但这些经验教训将帮你避免我早期的错误。
继续编码,保持好奇心,记住——你一定能行!