react-slingshot 与 GraphQL 乐观 UI:提升用户体验

react-slingshot 与 GraphQL 乐观 UI:提升用户体验

【免费下载链接】react-slingshot React + Redux starter kit / boilerplate with Babel, hot reloading, testing, linting and a working example app built in 【免费下载链接】react-slingshot 项目地址: https://gitcode.com/gh_mirrors/re/react-slingshot

你是否遇到过这样的情况:用户在表单中输入数据后,需要等待服务器响应才能看到结果?这种延迟不仅影响用户体验,还可能导致用户流失。本文将介绍如何使用 react-slingshot 结合 GraphQL 乐观 UI(Optimistic UI)技术,实现即时反馈的用户界面,让你的应用在用户操作后立即显示预期结果,大幅提升交互体验。

读完本文,你将学到:

  • 什么是乐观 UI 及其在实际应用中的价值
  • 如何在 react-slingshot 项目中集成 GraphQL
  • 实现乐观 UI 的具体步骤和最佳实践
  • 如何处理乐观更新失败的回滚机制

什么是乐观 UI?

乐观 UI(Optimistic UI)是一种前端开发技术,它在用户执行操作后立即更新界面,而不必等待服务器的确认响应。这种方式可以显著提升用户体验,让应用感觉更加流畅和响应迅速。

想象一下,当用户在你的应用中提交一个表单时,传统的做法是:

  1. 用户点击提交按钮
  2. 界面显示加载状态
  3. 等待服务器处理请求
  4. 服务器返回结果
  5. 更新界面显示结果

而采用乐观 UI 技术后,流程变为:

  1. 用户点击提交按钮
  2. 立即更新界面显示预期结果
  3. 后台异步发送请求到服务器
  4. 如果请求成功,什么都不用做(界面已经是最新状态)
  5. 如果请求失败,将界面回滚到之前的状态并提示错误

这种方式让用户感觉操作是即时完成的,大大减少了等待感。

react-slingshot 简介

react-slingshot 是一个 React + Redux starter kit,它包含了 Babel、热重载、测试、代码检查等功能,并提供了一个工作示例应用。它的目标是帮助开发者快速搭建 React 应用,而不必担心配置问题。

根据 README.md,react-slingshot 提供了以下核心功能:

  • 一键启动开发环境:npm start 命令即可启动开发服务器并自动打开浏览器
  • 快速反馈机制:保存文件后自动重新构建、运行代码检查和测试
  • 自动化生产构建:npm run build 命令可生成优化后的生产版本
  • 完整的技术栈:React、Redux、React Router、Babel、Webpack 等

GraphQL 与乐观 UI 的完美结合

GraphQL 是一种用于 API 的查询语言,它允许客户端精确指定需要获取的数据,从而减少网络传输和提升性能。当 GraphQL 与乐观 UI 结合使用时,可以创建出响应迅速且数据高效的应用。

集成 GraphQL 到 react-slingshot

要在 react-slingshot 中使用 GraphQL,我们需要添加以下依赖:

npm install @apollo/client graphql

然后,在应用的入口文件中配置 Apollo 客户端:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import Root from './components/Root';

const client = new ApolloClient({
  uri: '/graphql', // 你的 GraphQL API 端点
  cache: new InMemoryCache()
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <Root />
  </ApolloProvider>,
  document.getElementById('app')
);

实现乐观 UI 的步骤

下面我们以 react-slingshot 提供的燃油节省计算器示例应用为例,展示如何实现乐观 UI。原应用的燃油节省表单可以在 src/components/FuelSavingsForm.js 中找到。

1. 创建 GraphQL 查询和变更

首先,我们需要定义相关的 GraphQL 查询和变更。创建一个新文件 src/graphql/fuelSavings.js

import { gql } from '@apollo/client';

export const GET_FUEL_SAVINGS = gql`
  query GetFuelSavings {
    fuelSavings {
      id
      newMpg
      tradeMpg
      newPpg
      tradePpg
      milesDriven
      milesDrivenTimeframe
      dateModified
      savings {
        monthly
        annual
        threeYear
      }
    }
  }
`;

export const SAVE_FUEL_SAVINGS = gql`
  mutation SaveFuelSavings($input: FuelSavingsInput!) {
    saveFuelSavings(input: $input) {
      id
      newMpg
      tradeMpg
      newPpg
      tradePpg
      milesDriven
      milesDrivenTimeframe
      dateModified
      savings {
        monthly
        annual
        threeYear
      }
    }
  }
`;

2. 修改组件使用 Apollo Client

接下来,我们需要修改 FuelSavingsPage 容器组件,使用 Apollo Client 来管理数据和实现乐观 UI:

// src/components/containers/FuelSavingsPage.js
import React from 'react';
import { useQuery, useMutation } from '@apollo/client';
import FuelSavingsForm from '../FuelSavingsForm';
import { GET_FUEL_SAVINGS, SAVE_FUEL_SAVINGS } from '../../graphql/fuelSavings';
import { calculateSavings } from '../../utils/fuelSavings';

const FuelSavingsPage = () => {
  const { loading, error, data, client } = useQuery(GET_FUEL_SAVINGS);
  const [saveFuelSavings, { loading: saveLoading }] = useMutation(SAVE_FUEL_SAVINGS, {
    // 乐观更新函数
    update(cache, { data: { saveFuelSavings } }) {
      // 读取缓存中的当前数据
      const { fuelSavings } = cache.readQuery({ query: GET_FUEL_SAVINGS });
      
      // 更新缓存
      cache.writeQuery({
        query: GET_FUEL_SAVINGS,
        data: { fuelSavings: saveFuelSavings }
      });
    },
    // 发生错误时的回滚函数
    onError() {
      // 可以在这里显示错误提示
      alert('保存失败,请重试');
    }
  });

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const handleChange = (event) => {
    const { name, value } = event.target;
    
    // 乐观更新本地缓存
    const newData = {
      ...data.fuelSavings,
      [name]: value,
      savings: calculateSavings({
        ...data.fuelSavings,
        [name]: value
      })
    };
    
    client.writeQuery({
      query: GET_FUEL_SAVINGS,
      data: { fuelSavings: newData }
    });
  };

  const handleSave = () => {
    saveFuelSavings({ variables: { input: data.fuelSavings } });
  };

  return (
    <FuelSavingsForm
      fuelSavings={data.fuelSavings}
      onChange={handleChange}
      onSaveClick={handleSave}
      disabled={saveLoading}
    />
  );
};

export default FuelSavingsPage;

3. 优化用户体验的细节

为了进一步提升用户体验,我们可以添加以下优化:

  1. 添加加载状态指示器
  2. 实现表单输入的即时验证
  3. 添加操作成功的视觉反馈
  4. 优化错误处理和恢复机制

修改 FuelSavingsForm 组件,添加加载状态和错误提示:

// src/components/FuelSavingsForm.js
import React from 'react';
import { func, shape, number, string, bool } from 'prop-types';
import FuelSavingsResults from './FuelSavingsResults';
import FuelSavingsTextInput from './FuelSavingsTextInput';
import { fuelSavings } from '../types';

const FuelSavingsForm = ({ fuelSavings, onSaveClick, onChange, disabled }) => (
  <div>
    <h2>Fuel Savings Analysis</h2>
    <table>
      {/* 表单内容保持不变 */}
      <tbody>
        <tr>
          <td><label htmlFor="newMpg">New Vehicle MPG</label></td>
          <td><FuelSavingsTextInput onChange={onChange} name="newMpg" value={fuelSavings.newMpg}/>
          </td>
        </tr>
        <tr>
          <td><label htmlFor="tradeMpg">Trade-in MPG</label></td>
          <td><FuelSavingsTextInput onChange={onChange} name="tradeMpg" value={fuelSavings.tradeMpg}/>
          </td>
        </tr>
        {/* 其他表单项... */}
      </tbody>
    </table>

    <hr/>

    {fuelSavings.necessaryDataIsProvidedToCalculateSavings && <FuelSavingsResults savings={fuelSavings.savings}/>}
    
    <input 
      type="submit" 
      value={disabled ? "Saving..." : "Save"} 
      onClick={onSaveClick}
      disabled={disabled}
    />
  </div>
);

FuelSavingsForm.propTypes = {
  onSaveClick: func.isRequired,
  onChange: func.isRequired,
  fuelSavings: fuelSavings.isRequired,
  disabled: bool
};

FuelSavingsForm.defaultProps = {
  disabled: false
};

export default FuelSavingsForm;

乐观 UI 实现流程图

下面是乐观 UI 实现的流程图,展示了数据在 react-slingshot 应用中的流动过程:

mermaid

处理乐观更新失败的策略

尽管乐观 UI 可以提供出色的用户体验,但我们必须妥善处理可能的失败情况。以下是几种处理策略:

  1. 自动回滚:当服务器请求失败时,自动将界面回滚到之前的状态
  2. 用户确认回滚:向用户显示错误信息,并询问是否要保留更改或回滚
  3. 部分更新:只回滚失败的部分,保留其他成功的更改
  4. 重试机制:对于暂时性错误,自动重试几次后再回滚

以下是一个实现自动回滚和错误提示的示例:

const [saveFuelSavings, { loading: saveLoading }] = useMutation(SAVE_FUEL_SAVINGS, {
  // 乐观更新函数
  update(cache, { data: { saveFuelSavings } }) {
    // 保存当前状态用于可能的回滚
    const previousState = cache.readQuery({ query: GET_FUEL_SAVINGS });
    cache.writeQuery({
      query: GET_FUEL_SAVINGS,
      data: { fuelSavings: saveFuelSavings }
    });
    
    // 将先前状态存储在缓存中,以便在需要时回滚
    cache.writeQuery({
      query: GET_PREVIOUS_FUEL_SAVINGS,
      data: { previousFuelSavings: previousState.fuelSavings }
    });
  },
  // 发生错误时的回滚函数
  onError() {
    // 从缓存中读取先前状态
    const { previousFuelSavings } = cache.readQuery({ query: GET_PREVIOUS_FUEL_SAVINGS });
    
    // 回滚缓存
    cache.writeQuery({
      query: GET_FUEL_SAVINGS,
      data: { fuelSavings: previousFuelSavings }
    });
    
    // 显示错误提示
    alert('保存失败,请重试');
  }
});

总结

乐观 UI 是提升用户体验的强大技术,它可以让你的应用感觉更加流畅和响应迅速。通过将 react-slingshot 与 GraphQL 结合使用,我们可以轻松实现乐观 UI,为用户提供即时反馈。

本文介绍的主要内容:

  1. 乐观 UI 的概念和优势
  2. react-slingshot 的核心功能
  3. 如何在 react-slingshot 中集成 GraphQL
  4. 实现乐观 UI 的具体步骤
  5. 处理乐观更新失败的策略

要开始使用 react-slingshot,只需执行以下命令:

git clone https://gitcode.com/gh_mirrors/re/react-slingshot.git
cd react-slingshot
npm run setup
npm start -s

然后,你可以基于本文介绍的方法,为你的应用添加乐观 UI 功能,提升用户体验。

希望本文对你有所帮助!如果你有任何问题或建议,请随时在项目的 GitHub 仓库中提出 issue。

【免费下载链接】react-slingshot React + Redux starter kit / boilerplate with Babel, hot reloading, testing, linting and a working example app built in 【免费下载链接】react-slingshot 项目地址: https://gitcode.com/gh_mirrors/re/react-slingshot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值