我越来越厌倦了使用 Redux 带来的繁琐,特别是频繁跨层切换文件(夹)...
同时我也意识到多数时候我根本不需要“全局状态”,我的应用状态有清晰的边界,不同的“页面”组件维护自己的状态再通过某种方式传递给子组件就够了,根本不需要提升到全局。至于哪些应该是全局状态呢,我想可能是这些:色彩主题等(呃... 很难想到第二个)。
所以,我在 HitUP 项目的开发中,为了使以后的迭代能够愉快些,已经开始着手把部分状态从 Redux 中剥离出来到组件内部管理了。
HitUP 目前的核心组件就是 <GitHubTrending>
,用来展示 GitHub 上近期最热门的项目列表(Repo list),大致对应下图中我用紫色线标记的区域:
用户可以通过如下选项来控制 Repo list 的结果和展示方式:
- 编程语言(language):C++, Python, JavaScript 等
- 阶段(since):今天、本周或本月
- 视图类型(viewType):列表或格子视图
顺带说一下:
这个项目在我最初 fork 过来的时候(想了解项目背景,看这里),几乎一切都用全局状态管理,包括根据用户选项获取到的项目列表(Repo list),Repo list 其实是对 UI 交互状态的反映,确定了 UI 状态就确定了 Repo list, 我认为把这个放到全局状态毫无意义,还加重了 Redux 的负担,如果要跨设备同步用户配置就更麻烦了(Google 扩展的配置同步有限额)。
近日,我已经把几个关键用户选项抽离出来放在 <GitHubTrending>
组件内部自治管理了,包括 language
, since
和 viewType
,这几个选项都需要作持久化,用户下次打开页面会看到相同筛选条件的 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,又会导致短时间内界面切换过多,严重的撕裂感。
为了把问题阐释清楚,已经熬到了深夜。至于优化方案,我能想到的感觉不够优雅。想看看大家怎么看待我的场景、实现方案,对于我的困惑,有没有好的解决办法?
谢谢!