我们可以安装一个eslint插件来帮助我们避免这些问题。
- // 安装
- npm install eslint-plugin-react-hooks --save-dev
- // 配置
- {
- "plugins": [
- // ...
- "react-hooks"
- ],
- "rules": {
- // ...
- "react-hooks/rules-of-hooks": "error"
- }
- }
自定义Hook
像上面介绍的HOC和mixin一样,我们同样可以通过自定义的Hook将组件中类似的状态逻辑抽取出来。
自定义Hook非常简单,我们只需要定义一个函数,并且把相应需要的状态和effect封装进去,同时,Hook之间也是可以相互引用的。使用use开头命名自定义Hook,这样可以方便eslint进行检查。
下面我们看几个具体的Hook封装:
日志打点
我们可以使用上面封装的生命周期Hook。
- const useLogger = (componentName, ...params) => {
- useDidMount(() => {
- console.log(`${componentName}初始化`, ...params);
- });
- useUnMount(() => {
- console.log(`${componentName}卸载`, ...params);
- })
- useDidUpdate(() => {
- console.log(`${componentName}更新`, ...params);
- });
- };
- function Page1(props){
- useLogger('Page1',props);
- return (<div>...</div>)
- }
修改title
根据不同的页面名称修改页面title:
- function useTitle(title) {
- useEffect(
- () => {
- document.title = title;
- return () => (document.title = "主页");
- },
- [title]
- );
- }
- function Page1(props){
- useTitle('Page1');
- return (<div>...</div>)
- }
双向绑定
我们将表单onChange的逻辑抽取出来封装成一个Hook,这样所有需要进行双向绑定的表单组件都可以进行复用:
- function useBind(init) {
- let [value, setValue] = useState(init);
- let onChange = useCallback(function(event) {
- setValue(event.currentTarget.value);
- }, []);
- return {
- value,
- onChange
- };
- }
- function Page1(props){
- let value = useBind('');
- return <input {...value} />;
- }
当然,你可以向上面的HOC那样,结合context和form来封装一个更通用的双向绑定,有兴趣可以手动实现一下。
使用Hook的动机
减少状态逻辑复用的风险
Hook和Mixin在用法上有一定的相似之处,但是Mixin引入的逻辑和状态是可以相互覆盖的,而多个Hook之间互不影响,这让我们不需要在把一部分精力放在防止避免逻辑复用的冲突上。
在不遵守约定的情况下使用HOC也有可能带来一定冲突,比如props覆盖等等,使用Hook则可以避免这些问题。
避免地狱式嵌套
大量使用HOC的情况下让我们的代码变得嵌套层级非常深,使用HOC,我们可以实现扁平式的状态逻辑复用,而避免了大量的组件嵌套。
让组件更容易理解
(编辑:ASP站长网)
|