V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
simonguo
V2EX  ›  React

🎉 React Suite 5 发布了

  •  
  •   simonguo · Sep 26, 2021 · 5061 views
    This topic created in 1686 days ago, the information mentioned may be changed or developed.

    距离 v4 的第一个版本已经有接近两年的时间了,在这段时间里 v4 一共迭代了 30 多个版本,新增了许多特性。有越来越多的开发者开始使用 React Suite,并且参与功能开发与改进。还有一直对我们提出宝贵建议的开发者们,我们再次表示感谢。希望 React Suite 能够陪伴您的产品持续成长,同时也希望能够服务到更多的开发者。

    React Suite 5 提升了组件可访问性以及提供了更丰富可定制化的组件。以下将详细介绍新增特性以及如何从 4.x 升级到 5.0

    主要功能 ✨

    提升可访问(Accessibility)

    我们的希望可以让更多的用户在 React Suite 开发的产品上无障碍的使用。我们会在键盘操作、读屏设备等多个场景去改善 React Suite 提供的每一个组件。

    无障碍设计

    React Suite 遵循 WAI-ARIA 标准,对所有组件进行了重构,均具有开箱即用的适当属性和键盘交互功能。

    新增一套高对比度主题

    在 React Suite v4 我们参照 《 Web Content Accessibility Guidelines (WCAG) 》标准对颜色对比度的要求,对组件做了很大的改进,可以满足大多数用户。 我们还是希望在此基础上进行提升,并照顾到一小部分在视力上存在障碍的人群。 目前 React Suite 官方一共提供了 3 套主题 (light 、dark 、high-contrast)

    采用 SVG Icon 代替 Icon font

    Icon font 存在存在一些渲染上问题,导致图标模糊,需要载入字体文件,内容区域闪烁等问题。 为了更好的可访问性(Accessibility),我们决定优先采用 SVG Icon 。 并且能够友好的兼容第三方的图标资源。

    import GearIcon from "@rsuite/icons/Gear";
    
    render(<GearIcon />);
    
    // output
    <svg>
      <path d="M11.967 ..."></path>
      <path d="M8 10a2 2 0 10.001-3.999A2 2 0 008 10zm0 1a3 3 0 110-6 3 3 0 010 6z"></path>
    </svg>;
    

    支持 CSS 变量

    当前主流的浏览器都已经支持 CSS 变量,我们计划提供一套组件 CSS 变量配置,可以更方便的做主题自定义,主题切换。

    采用函数组件重构

    我们采用函数组件重构大部分的组件,采用 React Hooks 所带来的新特性,提升开发体验。

    按需加载

    在 v4 中导入组件的时候需要区分是 cjs 还是 esm 。 在 v5 中这是自动的。

    // v4: cjs
    import Button from "rsuite/lib/Button";
    // v4: esm
    import Button from "rsuite/es/Button";
    
    // v5
    import Button from "rsuite/Button";
    

    对 Form 表单的改进

    • 改进 Form 在纯文本视图的效果。
    • 对组件进行重命名。
    `FormGroup` 重命名为 `Form.Group`
    `FormControl` 重命名为 `Form.Control`
    `ControlLabel` 重命名为 `Form.ControlLabel`
    `ErrorMessage` 重命名为 `Form.ErrorMessage`
    `HelpBlock` 重命名为 `Form.HelpText`
    
    • 表单校验支持对象结构。
    const model = SchemaModel({
      username: StringType().isRequired("Username required"),
      tags: ArrayType().of(StringType("The tag should be a string").isRequired()),
      role: ObjectType.shape({
        name: StringType().isRequired("Name required"),
        permissions: ArrayType().isRequired("Permissions required"),
      }),
    });
    
    const checkResult = model.check({
      username: "foobar",
      tags: ["Sports", "Games", 10],
      role: { name: "administrator" },
    });
    
    console.log(checkResult);
    

    输出的数据结构:

    {
      username: { hasError: false },
      tags: {
        hasError: true,
        array: [
          { hasError: false },
          { hasError: false },
          { hasError: true, errorMessage: 'The tag should be a string' }
        ]
      },
      role: {
        hasError: true,
        object: {
          name: { hasError: false },
          permissions: { hasError: true, errorMessage: 'Permissions required' }
        }
      }
    };
    

    详细的使用教程请阅读: 表单校验Schema

    Avatar 新增支持 srcSet 、sizes 、imgProps 属性

    • srcSet: <img> 元素的 srcSet 属性。 使用此属性进行响应式图像显示。
    • sizes: <img> 元素的 sizes 属性。
    • imgProps: 如果该组件用于显示图像,则应用于 <img> 元素的属性。

    Slider 和 RangeSlider 支持 onChangeCommitted

    onChangeCommittedonChange 不同的点在于,onChange 是每一次值的改变都会触发,而 onChangeCommitted 是在 mouseup 事件触发后并且值发生了改变而触发的的回调。

    DatePicker 和 DateRangePicker 功能改进

    • DatePicker 与 DateRangePicker 支持键盘输入。 C392D1BC-AD67-4692-BAC0-A273A74DC564

    • DateRangePicker 之前只能选择日期,在 v5 中可以选择时间。

    <DateRangePicker format="yyyy-MM-dd HH:mm:ss" />
    

    Badge 支持 color 属性

    color 属性设置徽标提示点样式

    <Badge color="red">Red</Badge>
    <Badge color="orange">Orange</Badge>
    <Badge color="yellow">Yellow</Badge>
    <Badge color="green">Green</Badge>
    <Badge color="cyan">Cyan</Badge>
    <Badge color="blue">Blue</Badge>
    <Badge color="violet">Violet</Badge>
    <Badge color="red" />
    <Badge color="orange" />
    <Badge color="yellow" />
    <Badge color="green" />
    <Badge color="cyan" />
    <Badge color="blue" />
    <Badge color="violet" />
    <Badge color="blue" content="99+" />
    <Badge color="violet" content="NEW" />
    
    895ED4F3-F258-4A98-B48A-857F964A0EA0

    对 Table 的改进

    • 重构 Table

    使用 react hooks 重构了 Table, 并改进了表格滚动时的性能。 废弃了 onDataUpdatedbodyRef 属性

    对于一些要在表格内部渲染的组件,之前可以通过 bodyRef 获取表格的 body 容器。 现在我们可以通过 Tableref 直接获取容器。

    // v4
    const bodyRef = useRef();
    return (
      <>
        <Table
          bodyRef={(body) => {
            bodyRef.current = body;
          }}
        />
        <CheckPicker container={() => bodyRef.current} />
      </>
    );
    
    // v5
    const ref = useRef();
    return (
      <>
        <Table ref={ref} />
        <CheckPicker container={() => ref.current.body} />
      </>
    );
    
    • 支持 rowSpan 合并行

    image

    const data = [
      {
        city: "New Gust",
        name: "Janis",
        rowspan: 2,
      },
      {
        city: "New Gust",
        name: "Ernest Schuppe Anderson",
      },
      {
        city: "Maria Junctions",
        name: "Alessandra",
        rowspan: 3,
      },
      {
        city: "Maria Junctions",
        name: "Margret",
      },
      {
        city: "Maria Junctions",
        name: "Emiliano",
      },
    ];
    return (
      <Table data={data}>
        <Column
          width={100}
          verticalAlign="middle"
          rowSpan={(rowData) => {
            return rowData.rowspan;
          }}
        >
          <HeaderCell>Name</HeaderCell>
          <Cell dataKey="city" />
        </Column>
        <Column width={100}>
          <HeaderCell />
          <Cell dataKey="name" />
        </Column>
      </Table>
    );
    

    新增 TagInput 组件

    对 Input 的增强,支持输入标签,管理标签。

    import TagInput from "rsuite/TagInput";
    
    return (
      <TagInput
        defaultValue={["HTML", "CSS"]}
        trigger={["Enter", "Space", "Comma"]}
      />
    );
    
    TagInput

    对 Carousel 的改进

    <Carousel> 组件上支持 onSelect, onSlideEnd, onSlideStart 属性。

    • onSelect: 活动项更改时触发的回调
    • onSlideEnd: 幻灯片过渡结束时触发的回调
    • onSlideStart: 幻灯片过渡开始时触发的回调

    从 v4 升级到 v5 🚀

    接下来将为您提供指导,从而能够迅速的从 v4 升级到 v5 。

    准备工作

    • React 升级到 16.8 以上版本。
    • 确保您当前的 rsuite 版本是 4.*, 否则请先迁移到 v4

    运行 codemods

    对于大型项目来说升级组件的过程往往是痛苦的,我们准备了 codemods 来简化您的迁移体验 。

    使用说明

    npx rsuite-codemod <transform> <path> [...options]
    
    • transform - 转换的名称
    • path - 要转换的文件或目录。
    • 使用 --dry 选项进行试运行,并使用 --print 打印输出以进行比较。

    不兼容的变更

    不再对 IE 10 进行兼容支持

    我们将在 v5 版本中不再支持 IE 10,如果您需要继续在 IE 10 浏览器上使用请继续使用 v4 版本。

    - last 2 versions or > 1% or ie >= 10
    + last 2 versions or > 1% and not ie <11
    

    采用 SVG Icon 代替 Icon font

    使用 SVG Icon,使用前您需要安装 @rsuite/icons

    npm i @rsuite/icons
    
    // for rsuite v4
    import { Icon } from "rsuite";
    
    return <Icon icon="gear" />;
    
    // for rsuite v5
    import GearIcon from "@rsuite/icons/Gear";
    
    return <GearIcon />;
    

    移除了 size 属性,采用 fontSize 代替。

    // for rsuite v4
    return <Icon icon="gear" size="3x" />;
    
    // for rsuite v5
    return <GearIcon style={{ fontSize: "3em" }} />;
    

    size 属性值及其对应的 fontSize 值关系如下:

    • lg : 1.3333em
    • 2x : 2em
    • 3x : 3em
    • 4x : 4em
    • 5x : 5em

    date-fns 升级 v2

    在 React Suite 中使用了 date-fns 工具用于对日期格式、计算等等。基于 Unicode 标准,用于格式功能的新格式字符串有变更

    // for rsuite v4
    
    return (
      <>
        <DatePicker format="YYYY-MM-DD" />
        <DateRangePicker format="YYYY-MM-DD" />
      </>
    );
    
    // for rsuite v5
    
    return (
      <>
        <DatePicker format="yyyy-MM-dd" />
        <DateRangePicker format="yyyy-MM-dd" />
      </>
    );
    

    废弃 Alert 组件,用 toaster.push(<Message>) 代替

    所有的弹出的通知消息,都使用新的 API toaster 进行管理。Alert 组件将会被废弃,替代的方式是通过 toaster 与 Message 组合使用。 例如:

    // for rsuite v4
    Alert.info("description");
    
    // for rsutie v5
    toaster.push(
      <Message type="info" closable>
        description
      </Message>
    );
    

    删除一个消息或者清空消息

    // Remove message
    const key = toaster.push(
      <Message type="info" closable>
        description
      </Message>
    );
    toaster.remove(key);
    
    // Clear all messages
    toaster.clear();
    

    修改 Notification 使用方式

    // for rsuite v4
    Notification.info({
      title: "info",
      description: "description",
      duration: 4500,
      placement: "topStart",
    });
    
    // for rsuite v5
    toaster.push(
      <Notification type="info" header="info" duration={4500}>
        description
      </Notification>,
      { placement: "topStart" }
    );
    

    Form 相关组件重命名

    • FormGroup 重命名为 Form.Group
    • FormControl 重命名为 Form.Control
    • ControlLabel 重命名为 Form.ControlLabel
    • ErrorMessage 重命名为 Form.ErrorMessage
    • HelpBlock 重命名为 Form.HelpText

    所有组件的 componentClass 属性重命名为 as

    // for rsuite v4
    return <Button componentClass="span" />;
    
    // for rsuite v5
    return <Button as="span" />;
    

    默认关闭所有 Picker 的 virtualized

    所有的 Picker 的 virtualized 的默认值为 false。如果您希望继续在项目中使用,需要设置为 true

    <SelectPicker virtualized />
    

    改进异步更新子级的方式

    为了方便异步更新子节点,新增了一个 getChildren 属性。受影响的组件:

    • Cascader
    • MutilCascader
    • TreePicker
    • CheckTreePicker
    getChildren:(node: ItemDataType) => Promise<ItemDataType[]>
    
    function fetchNodes(id) {
      return new Promise((resolve) => {
        // fetch the child node data async
        resolve(childrenNodes);
      });
    }
    
    return (
      <>
        <Cascader getChildren={(node) => fetchNodes(node.id)} />
      </>
    );
    

    删除 Table.Pagination, 并增强 Pagination

    Table.Pagination 组件在本次更新中删除,请使用 Pagination 代替,新增了 layout 属性,用于自定义布局。

    // for rsuite v4
    return (
      <Table.Pagination
        lengthMenu={[
          { value: 50, label: 50 },
          { value: 100, label: 100 },
        ]}
        activePage={1}
        displayLength={20}
        total={100}
        onChangePage={handleChangePage}
        onChangeLength={handleChangeLength}
      />
    );
    
    // for rsuite v5
    return (
      <Pagination
        limit={50}
        limitOptions={[50, 100]}
        layout={["total", "-", "limit", "|", "pager", "skip"]}
        total={100}
        activePage={1}
        onChangePage={handleChangePage}
        onChangeLimit={handleChangeLimit}
      />
    );
    

    使用 CustomProvider 替换 IntlProvider

    // for rsuite v4
    import { IntlProvider } from "rsuite";
    import zhCN from "rsuite/lib/IntlProvider/locales/zh_CN";
    
    return (
      <IntlProvider locale={zhCN}>
        <App />
      </IntlProvider>
    );
    
    // for rsuite v5
    import { CustomProvider } from "rsuite";
    import zhCN from "rsuite/locales/zh_CN";
    
    return (
      <CustomProvider locale={zhCN}>
        <App />
      </CustomProvider>
    );
    

    废弃 <Sidenav> 组件的 activeKeyonSelect 属性

    <Sidenav> 组件总是和 <Nav> 组件配合使用。 您应当使用 <Nav> 组件的 activeKeyonSelect 属性。

    // for rsuite v4
    
    return (
      <Sidenav activeKey={activeKey} onSelect={setActiveKey}>
        <Sidenav.Body>
          <Nav>
            <Nav.Item>Nav item</Nav.Item>
            <Dropdown title="Dropdown">
              <Dropdown.Item>Dropdown item</Dropdown.Item>
            </Dropdown>
          </Nav>
        </Sidenav.Body>
      </Sidenav>
    );
    
    // for rsuite v5
    
    return (
      <Sidenav>
        <Sidenav.Body>
          <Nav activeKey={activeKey} onSelect={setActiveKey}>
            <Nav.Item>Nav item</Nav.Item>
            <Dropdown title="Dropdown">
              <Dropdown.Item>Dropdown item</Dropdown.Item>
            </Dropdown>
          </Nav>
        </Sidenav.Body>
      </Sidenav>
    );
    

    按需加载

    导入组件

    // v4
    import Button from "rsuite/lib/Button";
    import "rsuite/lib/Button/styles/index.less";
    
    // v5
    import Button from "rsuite/Button";
    import "rsuite/Button/styles/index.less";
    

    导入本地化语言包

    // v4
    import ruRU from "rsuite/lib/IntlProvider/locales/ru_RU";
    
    // v5
    import ruRU from "rsuite/locales/ru_RU";
    

    全局导入样式

    // v4
    import "rsuite/lib/styles/index.less"; // less
    import "rsuite/dist/styles/rsuite-default.css"; // css
    
    // v5
    import "rsuite/styles/index.less"; // less
    import "rsuite/dist/rsuite.min.css"; // or css
    import "rsuite/dist/rsuite-rtl.min.css"; // or rtl css
    

    废弃 <Dropdown> 组件的 renderTitle 属性

    废弃 renderTitle,取而代之的是 renderToggle

    //v4
    return (
      <Dropdown
        renderTitle={() => (
          <IconButton appearance="primary" icon={<Icon icon="plus" />} circle />
        )}
      >
        ...
      </Dropdown>
    );
    
    //v5
    return (
      <Dropdown
        renderToggle={(props, ref) => (
          <IconButton
            {...props}
            ref={ref}
            icon={<PlusIcon />}
            circle
            appearance="primary"
          />
        )}
      >
        ...
      </Dropdown>
    );
    

    open/close 代替 show/hide

    在 v4 版本中组件的属性命名同时存在 open/closeshow/hide 的使用。在 v5 中将命名统一起来。

    // v4
    
    <Modal show="{true}" onShow="{...}" onHide="{...}" />
    <Drawer show="{true}" onShow="{...}" onHide="{...}" />
    <Whisper delayHide="{1000}" delayShow="{1000}" />
    
    // v5
    <Modal open="{true}" onOpen="{...}" onClose="{...}" />
    <Drawer open="{true}" onOpen="{...}" onClose="{...}" />
    <Whisper delayClose="{1000}" delayOpen="{1000}" />
    

    支持 React Suite

    如果您喜欢 React Suite,可以通过以下方式支持我们:

    • Star 这个项目。
    • 如果您在您的项目中使用了 React Suite,欢迎在这里留言
    • OpenCollective 上赞助我们。
    10 replies    2021-10-13 14:26:51 +08:00
    niuroumian
        1
    niuroumian  
       Sep 26, 2021
    请问 table 组件是否支持 header filter 功能?
    ragnaroks
        2
    ragnaroks  
       Sep 26, 2021
    以前用过,总觉得顶部导航和边栏导航不太好看
    eyeix
        3
    eyeix  
       Sep 26, 2021 via iPhone
    之前用过,风格比较舒服,很喜欢💯
    ericgui
        4
    ericgui  
       Sep 27, 2021
    支持
    simonguo
        5
    simonguo  
    OP
       Sep 27, 2021
    @ericgui @lrvinye 谢谢
    @ragnaroks 可以个性化定制
    @niuroumian 目前不支持,不过 table 的 API 都比较方便,通过和 CheckPicker 组合,实现一个 filter 不是什么麻烦的事情。
    yazoox
        6
    yazoox  
       Sep 28, 2021
    有没有使用 theme 和 language 的具体例子?
    zikkeung
        7
    zikkeung  
       Sep 28, 2021
    跟知乎的贴一模一样
    huai
        8
    huai  
       Oct 12, 2021
    Modal 或者 drawer 隐藏后 默认销毁?能否加开关控制呢
    simonguo
        9
    simonguo  
    OP
       Oct 13, 2021
    @yazoox examples 里有相关的例子,不过示例还没有升级到最新版本,可以先参考,最近有计划把示例全部更新一下 https://github.com/rsuite/rsuite/tree/main/examples

    @zikkeung 是的

    @huai 没有对应的开关,默认情况下不渲染的组件不会生成 DOM 。 不知道你这样的需求的应用场景是什么?
    huai
        10
    huai  
       Oct 13, 2021
    @simonguo #9 无非是 modal 里用来做展示得,生成出来得代价比较昂贵。 比如 modal 里,展示某个组件,这个组件需要获取数据等等
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2978 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 75ms · UTC 07:08 · PVG 15:08 · LAX 00:08 · JFK 03:08
    ♥ Do have faith in what you're doing.