[React][Redux][HitUP] 我尝试在组件内部自治管理状态(包括持久化)后遇到的困惑

我越来越厌倦了使用 Redux 带来的繁琐,特别是频繁跨层切换文件(夹)...

同时我也意识到多数时候我根本不需要“全局状态”,我的应用状态有清晰的边界,不同的“页面”组件维护自己的状态再通过某种方式传递给子组件就够了,根本不需要提升到全局。至于哪些应该是全局状态呢,我想可能是这些:色彩主题等(呃... 很难想到第二个)。

所以,我在 HitUP 项目的开发中,为了使以后的迭代能够愉快些,已经开始着手把部分状态从 Redux 中剥离出来到组件内部管理了。


HitUP 目前的核心组件就是 <GitHubTrending>,用来展示 GitHub 上近期最热门的项目列表(Repo list),大致对应下图中我用紫色线标记的区域:

HitUP/&lt;GitHubTrending&gt;

用户可以通过如下选项来控制 Repo list 的结果和展示方式:

  • 编程语言(language):C++, Python, JavaScript 等
  • 阶段(since):今天、本周或本月
  • 视图类型(viewType):列表或格子视图
顺带说一下:
这个项目在我最初 fork 过来的时候(想了解项目背景,看这里),几乎一切都用全局状态管理,包括根据用户选项获取到的项目列表(Repo list),Repo list 其实是对 UI 交互状态的反映,确定了 UI 状态就确定了 Repo list, 我认为把这个放到全局状态毫无意义,还加重了 Redux 的负担,如果要跨设备同步用户配置就更麻烦了(Google 扩展的配置同步有限额)。

近日,我已经把几个关键用户选项抽离出来放在 <GitHubTrending> 组件内部自治管理了,包括 language, sinceviewType,这几个选项都需要作持久化,用户下次打开页面会看到相同筛选条件的 Repo list.

我的思路是:把加载并保存用户选项的细节实现成一个 自定义 React Hook,叫做 usePreference. 未来除了 <GitHubTrending>,我还打算添加其它的榜单功能,比如 <GitHubRanking>, 理想情况下这些组件使用 usePreference 时只需要传递各自的存储键(persistKey)和默认配置数据就行了:

// 未来的 GitHubRanking 组件可能包含下面的配置项:
function GitHubRanking(props) {
  const [state, setState] = useState({
    processing: true,
    repositories: [],
    error: null,
  });

  const { preference, setPreference } = usePreference({
    language: 'Python',
    period: ['2019-05-25T00:00:00Z', '2019-06-01T00:00:00Z'],
    topics: ['linux']
    viewType: 'grid',
  }, {persistKey: 'HitUP:preference:GitHubRanking'});

  return <div>...</div>
}

针对已有的 <GitHubTrending> 组件,改造已经完成了。


终于把情况把背景介绍完了,长舒一口气。。。

那么我遇到了什么新的困惑呢?

先来看看以前的情况,在重度使用 Redux 并配合 redux-persist 做状态管理的时候,我们的 app.js 中有这种写法:

    return <Provider store={ store }>
      <PersistGate loading={ <Launcher/> } persistor={ persist }>
        <ThemeWrapper/>
      </PersistGate>
    </Provider>

注意其中的 loading={ <Launcher/> },在全局状态未准备好之前可以展示一个 LoadingSpin

在全局状态就绪后,如果不需要从网络获取获取数据(我对 GitHub 趋势数据做了本地缓存),那么整个页面是一瞬间完整展示的(与下文中的”阶段化“形成对比)


当我把 <GitHubTrending> 的几个状态交给组件自己管理后,整个页面的加载呈现明显的阶段化,因为我是首次进入组件的生命周期才开始异步从某个存储引擎(比如 localStorage)加载配置的,而在加载配置的过程中,页面的其它组件(特别是 <TopNav>)已经渲染出来了。而 <GitHubTrending> 对应的区域只能是空白的,加载配置的时间窗口其实很短,可能只能 0.1~0.2 秒,但这种局部白屏却能明显的感受到,有种很生硬的感觉,如果我在这个时间窗口放一个 Loading Spin,又会导致短时间内界面切换过多,严重的撕裂感。

为了把问题阐释清楚,已经熬到了深夜。至于优化方案,我能想到的感觉不够优雅。想看看大家怎么看待我的场景、实现方案,对于我的困惑,有没有好的解决办法?

谢谢!

阅读 1.6k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题