先说说最基础的函数组件和类组件吧。现在社区里函数组件加Hooks是大趋势,但老项目中类组件还是一抓一大把。函数组件写起来确实爽,代码量少,看着也清爽。但刚上手的时候,很多人容易掉进一个坑:以为函数组件就是无状态的。这可是老黄历了,自从Hooks出来之后,函数组件啥都能干,状态、生命周期,一个都不少。
类组件嘛,现在新项目可能用得少了,但维护老代码的时候绕不开。那个constructor里的super(props),多少人曾经忘记写过?还有this绑定问题,简直是新手的噩梦。箭头函数、bind、class properties,各种写法都有,团队里要是没个统一规范,代码能写得五花八门。
说到状态管理,useState这个Hook真是让人又爱又恨。用起来简单,但陷阱也不少。比如状态更新是异步的,连续set同一个状态,拿到的还是旧值。还有啊,对象和数组的状态更新,必须返回一个新对象,直接修改原对象然后setState,页面根本不更新,这种bug找起来能让人崩溃。
useEffect这个Hook更是重灾区。依赖数组没写对,要么是无限循环,要么是状态滞后。空数组、不传第二个参数、依赖项写全,这三种情况分别对应什么行为,好多人都是一知半解。清理函数也是个容易忽略的地方,订阅、定时器要是不清理,内存泄漏分分钟的事。
组件通信这块,父传子用props大家都懂,但子传父就得靠回调函数了。跨层级通信的话,Context API用起来方便,但性能问题得注意。Provider的value一变,所有消费这个Context的组件都要重新渲染,就算用了memo也可能拦不住。
说到memo,优化相关的知识点真的需要好好掌握。memo、useMemo、useCallback这三个兄弟,用好了性能提升明显,用不好反而增加负担。子组件用memo包了,父组件传的props却每次都是新对象,那memo就白用了。useCallback的依赖数组也是坑,漏写依赖会导致闭包问题,多写依赖又可能造成不必要的更新。
生命周期在函数组件里怎么对应?useEffect可以模拟componentDidMount、componentDidUpdate和componentWillUnmount,但思维模式得转变。类组件是"什么时候做什么事",函数组件加Hooks是"根据什么状态做什么事"。这个思维转变不过来,Hooks用起来就会觉得别扭。
自定义Hook才是真的香。把可复用的逻辑抽出来,多个组件之间共享,代码立马干净很多。不过起名字是个技术活,use开头是必须的,名字要能准确表达这个Hook是干什么的。逻辑抽得恰到好处很重要,抽得太细用起来麻烦,抽得太粗复用性又不好。
最后说说错误边界,这个用类组件才能实现,通过componentDidCatch和getDerivedStateFromError。虽然平时不太起眼,但在生产环境中真的很重要,能防止整个应用因为某个组件出错而崩溃。
实际项目中,组件的划分粒度也很考验经验。分得太粗,复用性差;分得太细,又显得过度设计。怎么把握这个度?一般来说,如果一个组件开始变得复杂,或者某部分逻辑可能被复用,就可以考虑拆分了。组件的props设计也要有前瞻性,既要满足当前需求,又要考虑将来可能的需求变化。
总之,React组件看似简单,真要玩转还得下不少功夫。多写多踩坑,慢慢就有感觉了。最好的学习方式就是实际项目,遇到问题解决问题,经验就这么积累起来了。