从零开始打造可复用的React组件并实现深度定制化

Top丶春芹 组件 阅读 2,480
赞 12 收藏
二维码
手机扫码查看
反馈

我的写法,亲测靠谱

先说说我常用的组件定制写法吧。最近一个项目里用到了这样的方式:

从零开始打造可复用的React组件并实现深度定制化

import BaseButton from './BaseButton';

const CustomButton = ({ color, size, children, ...rest }) => {
  const styles = {
    small: { padding: '5px 10px', fontSize: '12px' },
    medium: { padding: '8px 16px', fontSize: '14px' },
    large: { padding: '12px 24px', fontSize: '16px' }
  };

  return (
    <BaseButton 
      style={{ 
        backgroundColor: color, 
        ...styles[size] 
      }}
      {...rest}
    >
      {children}
    </BaseButton>
  );
};

这种方式有几个好处:首先是把样式和逻辑分离得很清楚,每个size都对应一套固定样式,维护起来特别方便。其次是通过解构传参,让组件的扩展性很强。

我一般还会在BaseButton里做一些基础封装,比如:

const BaseButton = ({ onClick, disabled, className, children, ...props }) => {
  return (
    <button
      className={base-btn ${className || &#039;&#039;}}
      onClick={disabled ? undefined : onClick}
      disabled={disabled}
      {...props}
    >
      {children}
    </button>
  );
};

这里加了个基础的disabled处理,防止误触。别看这代码简单,能省不少事。

这几种错误写法,别再踩坑了

说真的,踩过的坑太多了。最常见的就是直接在组件里硬编码样式:

const BadButton = () => (
  <button style={{ backgroundColor: '#ff0000', padding: '10px', border: 'none' }}>
    Click me
  </button>
);

这种写法看着简单,但是一旦要改样式就得挨个找组件修改,折腾死人。

还有种常见的错误是滥用props:

const AnotherBadButton = (props) => (
  <button 
    style={{ 
      backgroundColor: props.bgColor,
      color: props.textColor,
      padding: props.padding,
      margin: props.margin,
      // 各种乱传...
    }}
  >
    {props.children}
  </button>
);

这样写看似灵活,实际上太随意了,很容易导致组件行为不可控,建议避开这种写法。

实际项目中的坑

说个最近遇到的坑。有个需求是要根据不同权限显示不同样式的按钮,一开始我是这么写的:

const PermissionButton = ({ userRole, ...props }) => {
  if (userRole === 'admin') {
    return <AdminButton {...props} />;
  } else if (userRole === 'editor') {
    return <EditorButton {...props} />;
  }
  return <BasicButton {...props} />;
};

看起来没毛病对吧?结果上线后发现,权限变更时页面不会实时更新。折腾了半天才发现,应该用React的状态管理来处理:

const [role, setRole] = useState(userRole);

useEffect(() => {
  const checkPermission = async () => {
    const response = await fetch('https://jztheme.com/api/permission');
    const data = await response.json();
    setRole(data.role);
  };
  checkPermission();
}, []);

这才解决了问题。所以状态相关的逻辑一定要慎重处理

性能优化的小技巧

说到性能,有件事得提醒下。之前为了给按钮加loading效果,直接在组件里用了setTimeout:

const LoadingButton = ({ isLoading }) => {
const [text, setText] = useState('Submit');

useEffect(() => {
if (isLoading) {
setText('Loading...');
setTimeout(() => setText('Submit'), 3000); // 这里有问题
}
}, [isLoading]);

return <button>{text}</button>;
};
`&gt;
&lt;p&gt;结果发现切换太快会导致状态混乱。后来改成这样:&lt;/p&gt;</code></pre>javascript
const LoadingButton = ({ isLoading }) => {
const timerRef = useRef();

useEffect(() => {
if (isLoading) {
timerRef.current = setTimeout(() => {
// 处理逻辑
}, 3000);
}

return () => clearTimeout(timerRef.current);
}, [isLoading]);

return <button>{isLoading ? 'Loading...' : 'Submit'}</button>;
};
`>

用useRef存定时器ID,确保每次都能正确清除,这个小改动让组件稳定多了。

结尾唠叨几句

以上是我总结的最佳实践,当然方案不是完美的,但确实是实战中摸索出来的比较靠谱的写法。组件定制这块水挺深的,不同的项目可能需要不同的处理方式。

我个人觉得,写组件最重要的是:明确职责边界。该组件做的事就做好,不该管的别瞎掺和。像样式这种东西,能抽出去就抽出去,别全堆在组件里。

有更好的方案欢迎评论区交流,或者你有遇到什么奇葩需求也可以分享下,大家一起讨论。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论