🤠 2023年了你还不会乐观 UI 吗?

阿轩的BUG
文章191
评论56
标签101
站点日志
作者总数:1位
置顶文章:0篇
标签总数:101条
文章总数:196篇
评论总数:56条
微语总数:201条
运行天数:2317天
最近更新:2026-07-28
文章标签
最新评论
Sherlock
2025-08-21
不是应该打包成apk文件吗,怎么突然就运行编译了,下一步呢
老金er
2025-05-25
人生设计非常必要,在信息化发达的今天,周围大部分人依然只能过着人生工程模式生活,长时间生活洗礼后,尽管“人生工程”已经不再适合很多人,他们也无法做出任何改变,人生设计给我们提供了新的思路,值得尝试
赏帮赚
2025-05-25
职场太多的尔虞我诈
三笑
2024-08-16
emlog6.0.1可以升级支持吗?
pony
2024-07-08
这篇文章提供了一种新的人生规划方法——"人生设计",它借鉴了产品设计的理念,鼓励人们以创造性和探索性的方式思考和规划自己的生活。以下是对这篇文章的几个评价维度: 创新性:将产品设计的理念应用于人生规划是一个新颖的视角,为人们提供了一种跳出传统生活轨迹,探索个性化生活路径的方法。 实用性:文章不仅提出了理念,还详细介绍了具体的实施步骤,包括自我评估、制定计划、原型设计和实践选择等,具有很强的操作性。 启发性:通过强调好奇心、不断尝试、重新定义问题等心态,文章鼓励人们打破常规,勇于探索未知,这对于激发个人潜能和创造力具有积极作用。 适应性:"人生设计"理念适用于不同人生阶段和不同背景的人,无论是希望从头开始的人,还是已经取得一定成就但希望探索新方向的人,都可以从中获得启发。 情感共鸣:文章对许多人对传统生活轨迹的不满和对改变的渴望进行了深刻的洞察,能够引起读者的共鸣。 可持续性:人生设计强调的是一个持续迭代和试错的过程,这与现实生活的发展规律相吻合,有助于人们在不断变化的环境中做出适应性调整。 教育意义:作为一种人生规划方法,"人生设计"可以作为教育的一部分,帮助年轻人更早地学会自我探索和规划,为未来的生活和职业发展打下基础。 局限性:尽管"人生设计"提供了一种新的思考框架,但它可能需要个人具备一定的自我认知和反思能力,对于一些缺乏自我探索经验的人来说,可能需要额外的指导和支持。 总体来说,这篇文章提供了一种有价值的人生规划方法,对于那些渴望改变、寻求个性化生活的人来说,是一种有益的参考和指导。
首页值得一看 🔍️

什么是乐观 UI

乐观 UI ( optimistic UI ) 是一种 UI 设计方式 , 它在用户执行操作后 , 不用等待服务器响应 , 立即更新 UI。 如果操作失败 , 则回滚 UI 到之前的状态。

为什么要使用乐观 UI

  • 给用户即时的反馈,界面感觉很响应迅速,带来很好的用户体验 provider a responsive user experience.
  • 由于界面很流畅,可以更好地吸引和维持用户的注意力与参与。keeps the user engaged.
  • 尽管后端处理需要时间,但用户基本无感知,因为UI已经立即更新了 reduces the perceived latency.

乐观 UI 的缺点

  • 如果用户在操作后离开页面,则可能会出现不一致的状态。inconsistent state if the user leaves the page after the operation.
  • 如果操作失败,则需要回滚 rollback 。这可能会导致复杂的代码,因为您需要跟踪所有可能的回滚操作。complex code to track all possible rollback operations.

如何在你的项目中实践乐观 UI

下面我将用两个简单的例子来说明如何在你的项目中实践乐观 UI。

1. 点赞评论以及收藏

image.png

在收藏,点赞,评论或者是在列表中更新状态,是乐观 UI 应用最普遍的场景,使用 swr 可以很方便实现这个功能

import useSWR from 'swr'

// req_get 是 axios 的封装,你可以换成自己项目中的请求
const fetcher = url => req_get(url);
function useList() {
  const { data, isLoading} = useSWR('/api/list', fetcher)
  // 建议请求的后台接口都放在这里统一处理成自己想要的格式
  return { data: data.list,isLoading }
}

首先我们准备上面的列表接口, 使用 swr 加乐观 UI 可以避免大多数本地状态管理的问题,我们不需要使用 useState 来管理本地状态,只需要在请求成功后验证数据即可

import {mutate} from 'swr';

function List() {
  const {data, isLoading} = useList();

  const handleLike = (id) => {
    const optimisticData = data.map((item) => {
      if (item.id === id) {
        return {
          ...item,
          like: item.like + 1,
        };
      }
      return item;
    });
    const options = {
      optimisticData,
      rollbackOnError(error) {
        // 如果超时中止请求的错误,不执行回滚
        return error.name !== 'AbortError';
      },
    };
    // 立即更新本地数据
    // 发送一个请求以更新数据
    // 触发重新验证(重新请求)确保本地数据正确
    // req_post 应该是一个 promise 或者异步函数以处理远程数据更改,它应该返回更新后的数据
    mutate("/api/list", req_post('/api/like', {id}), options);
  };
  return (
    <div>
      {isLoading ? (
        <div>loading...</div>
      ) : (
        data.map((item) => (
          <div key={item.id}>
            <span>{item.title}</span>
            <span>{item.like}</span>
            <button onClick={() => handleLike(item.id)}>点赞</button>
          </div>
        ))
      )}
    </div>
  );
}

可以看到如果后端愿意配合,将执行操作后的数据返回,我们就可以先直接更新本地数据,然后再发送请求,最后再重新验证数据,这样就可以实现乐观 UI 了。

2. 拖拽排序

image.png

拖拽排序是一个很常见的功能,也是乐观 UI 的一个很好的应用场景,我们可以使用 react-beautiful-dnd 来实现这个功能

import {DragDropContext, Droppable, Draggable} from 'react-beautiful-dnd';

const reorder = (list, startIndex, endIndex) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);
  return result;
};

function List() {
  // 不再需要 useState 管理本地状态
  const { data:list, isLoading} = useList();
  const handleDragEnd = (result) => {
    if (!result.destination) {
      return;
    }
    const items = reorder(
      list,
      result.source.index,
      result.destination.index
    );
    const options = {
      optimisticData: items,
    };
    // req_post 也是 axios 的封装,你可以换成自己项目中的请求,需要返回更新后的数据
    mutate("/api/list", req_post('/api/sort', {list: items}), options);
  };

  return (
    <DragDropContext onDragEnd={handleDragEnd}>
      <Droppable droppableId="droppable">
        {(provided, snapshot) => (
          <div ref={provided.innerRef} {...provided.droppableProps}>
            {list.map((item, index) => (
              <Draggable key={item.id} draggableId={item.id} index={index}>
                {(provided, snapshot) => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    <span>{item.title}</span>
                  </div>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
}

总结

乐观 UI 是一个很好的用户体验,但是它也有一些缺点,在实际项目中,我们需要根据实际情况来决定是否使用乐观 UI 。如果你的项目中有类似的场景,可以尝试使用 swr 来实现乐观 UI

上一篇
👻 业务仔就写好业务,内存泄漏不是你该关心的问题
下一篇
💡 提升JavaScript 加载速度的10种方式