这是一篇译文,主要内容为 React 组件、Hook 和性能方面需要学习和注意的点,没有深入到各个细节,算是一个 Study List,原文分为 part1 和 part2,part1 比较基础,这里主要是 part2,链接可以在最后找到。
受控组件与非受控组件
简单来说,受控组件使用 state 进行管理,而非受控组件不关心值如何变化,使用 ref 获取 value 即可。具体看代码即可
class ControlledInput extends React.Component {
state = {
value: ""
};
onChange = (e) => this.setState({ value: e.target.value });
render() {
return (
<input value={this.state.value} onChange={this.onChange}/>
);
}
}
class UncontrolledInput extends React.Component {
input = React.createRef();
getValue = () => {
console.log(this.input.current.value);
};
render() {
return (
<input ref={this.input}/>
);
}
}
那么我们该如何选择呢?受控组件适合绝大多数场景,但也有例外,比如 file input
,因为它的值是只读的,不能用代码进行设定,必须由用户进行交互。受控组件更加可读,能更友好的工作,比如即时的错误提示。
refs
refs 能获取到 Component 或 DOM Element 实例,应该尽量避免使用它,因为它会导致代码可读性变差,而且打破了 top-to-bottom 数据流。如果有更好的方式去解决问题,就要轻易使用它,比如提升状态或函数至父组件。
有三种方式
- 使用字符串:避免使用,被淘汰
- 在 ref 属性中使用回调函数
- React.createRef()
如果想获得深层次的元素的时候,比如高阶组件中,我们就需要用到 React.forwardRef 进行 ref 转发
function withNewReference(Component) {
class Hoc extends React.Component {
render() {
const {forwardedRef, ...props} = this.props;
return <Component ref={forwardedRef} {...props}/>;
}
}
return React.forwardRef((props, ref) => {
return <Hoc {...props} forwardedRef={ref} />;
});
}
错误边界
如果组件运行错误,如果父组件没有错误边界,会导致整个应用错误
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logToErrorLogger(error, info);
}
render() {
if (this.state.hasError) {
return <div>Help, something went wrong.</div>;
}
return this.props.children;
}
}
HOC
想必你已经使用过 HOC 模式了,withNavigation
, connect
, withRouter
也是基于 HOC 的实现。
这里有一些使用高阶组件推荐做的和避免做的
- 为 HOC 增加 display name
- 不要在 render 函数中创建 HOC:你应该使用已经增强的组件,而不是在 render 中创建 HOC 组件,否则重新挂载会丢失当前 state
- static 函数不会被复制,如果你需要的话,此时你需要手动复制
- refs 不会传递,需要使用 React.forwardRef
styling
CRA 内置继承 CSS Modules,直接命名为 xxx.module.css 即可启用。
另一个解决有名的解决方案就是:CSS-in-JS。
hooks
hooks 是自重写依赖,最让人期待的特性了,这里就不说太多了,这是我近期学习的重点。
类型检查
在 React 15.5 后,PropTypes 作为一个独立的包需要独立安装,通过 static propTypes 指名类型,配合 defaultProps 属性声明默认参数,可以用来消除 PropTypes 产生的 warning。
另外的可选就是 Flow 和 TypeScript,如今 TypeScript 更加流行。
性能
最基础和明显的就是,你需要将 DefinePlugin 切换成 production,添加 UglifyJsPlugin,如果是 CRA 创建的项目,你只要运行 npm run build
即可。
针对 JS 文件,你可能会经历如下历程
- 文件较少时,只需要 bundle.js
- vendor + bundle
- vendor + smallest required part + import things when they are needed.
介绍两个用来发现性能问题的工具
- Chrome Performance Tab
- DevTools Profiler
Code Splitting
主要使用 Webpack 提供的动态 import()
React.lazy() 实现懒加载,React.suspense() 在懒加载完成之前显示其他组件