Live Note

Remain optimistic

作为一名长期与 React 生态系统打交道的开发者,我最近遭遇了一个极其诡异的 bug——那种会让你怀疑自己理解能力、甚至怀疑整个世界物理定律的 bug。今天我想详细记录这个奇特的现象,希望能帮助遇到类似问题的开发者,同时也为未来的自己留下一个案例参考。

Read more »

作为一名经历了多个产品周期的从业者,我深深理解产品设计从简洁到臃肿的无奈转变过程。半年前将旧项目交由团队负责时,它是一个清晰明了的应用,而今再审视,它已变成一个让我这个创始人都不知所措的庞然大物。

一个令人不安的产品现实

当我重新打开自家的 APP,那种熟悉的失落感再次袭来——图标堆积如山,功能层级深不见底,操作路径错综复杂。更讽刺的是,作为产品的最初设计者,我竟需要求助说明文档才能完成基本操作。这绝非个案,而是一个普遍的产品进化轨迹:初创时的简洁与专注逐渐被功能膨胀侵蚀,最终滑向复杂性的深渊。

功能蔓延(Feature Creep)现象不仅困扰着我的产品,更是全行业的通病。研究显示,85%的大型应用在第三年版本时会变得比初代复杂 3 倍以上(Cappenini, 2021)。用户调研数据更令人深思,62%的消费者表示会因为应用”过于复杂”而放弃使用(Adobe, 2022)。

功能膨胀的深层动因

竞争驱动的设计陷阱

市场的现实残酷而直接:竞争对手上了新功能,我们的销售团队就开始施压;客户随口一提的需求,被当作”重要反馈”列入开发清单。以 Spotify 为例,这个曾经极简的音乐平台如今变成了集成播客、有声书、短视频的”万能娱乐中心”,其核心的音乐搜索体验反而退居次席。

这种竞争驱动设计源于两个主要心理:

  1. “别人有我们也必须有”的防御心态
  2. “功能越多越能吸引客户”的错觉

需求传递的失真效应

客户反馈往往是表象而非本质。当用户说”希望有更多分析图表”,真实诉求可能是”现有的数据展示不够清晰”。微软 Teams 的案例极具代表性——早期版本功能简洁,用户要求新增功能;当功能达到 300+时,75%的用户却只使用其中 20 项核心功能(Microsoft 内部数据)。

Read more »

作为前端开发者,我们经常需要处理长列表数据的展示,而性能优化是其中关键的一环。本文将分享我在使用 antd-mobile 时整合虚拟列表(Virtual List)的实践经历,特别是遇到的坑和解决方案。

效果展示:

为什么需要 Virtual List

传统列表渲染会一次性渲染所有元素,当数据量很大时,会导致:

  1. 页面加载缓慢 2.内存占用高
  2. 滚动卡顿
  3. DOM 节点过多影响性能

虚拟列表通过仅渲染可视区域内的元素来解决这些问题,显著提升性能。

技术选型

尝试 react-virtuoso

我的第一个尝试是使用 react-virtuoso,一个现代化的虚拟列表库:

1
2
3
import { Virtuoso } from "react-virtuoso";

<Virtuoso data={data} itemContent={(index) => <Item item={data[index]} />} />;

遇到的坑点:当与 antd-mobile 的PullToRefresh组件结合使用时,发现下拉刷新会”吞噬”列表的滚动事件,导致列表无法滚动。这可能是因为两者都在尝试控制滚动行为,产生了冲突。

切换到 react-virtualized

由于上述问题,我转向了更成熟的 react-virtualized 库,它提供了 List 组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {
List as VirtualList,
AutoSizer,
WindowScroller,
} from "react-virtualized";

<WindowScroller>
{({ height, scrollTop, isScrolling }) => (
<VirtualList
autoHeight
height={height}
width={width}
rowCount={data.length}
rowHeight={120}
rowRenderer={rowRender}
scrollTop={scrollTop}
isScrolling={isScrolling}
/>
)}
</WindowScroller>;
Read more »

问题现象:升级到 Android 15 后,你的 React Native 应用底部安全区域失效了?当安卓系统导航栏覆盖应用内容时,这不再是个别现象——Android 15 的Edge-to-Edge设计策略强制改变了窗口布局规则。本文将提供完整的诊断和修复方案。

问题根源分析

Android 15 的关键行为变更

  1. 默认强制 Edge-to-Edge 渲染

    • 所有应用内容默认延伸至系统导航栏后方
    • SYSTEM_BAR_BACKGROUNDS 属性不再自动处理安全区域
  2. window.setDecorFitsSystemWindows(false) 成为强制标准

    • 需手动处理 Insets(内容插入区域)
    • 传统安全区域计算库失效的原因

完整解决方案

第一步:更新安全区域处理库

1
2
# 更新到支持Android 15的版本(至少4.5.0+)
yarn add react-native-safe-area-context@latest

第二步:改造根组件结构

App.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";

export default function App() {
return (
<SafeAreaProvider
initialMetrics={{
insets: { top: 0, bottom: 48 }, // Android 15最小安全高度
}}
>
{/* 使用新边距处理方式 */}
<EdgeToEdgeWrapper>
<MainAppContent />
</EdgeToEdgeWrapper>
</SafeAreaProvider>
);
}

第三步:创建 Android 15 专用适配组件

EdgeToEdgeWrapper.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { View, Platform, StatusBar } from "react-native";

export default function EdgeToEdgeWrapper({ children }) {
const insets = useSafeAreaInsets();

return (
<View
style={{
flex: 1,
paddingTop:
Platform.OS === "android" ? StatusBar.currentHeight : insets.top,
paddingBottom: insets.bottom > 0 ? insets.bottom : 48, // 兼容旧设备
}}
>
{children}

{/* 底部安全区域视觉指示器 (DEBUG模式使用) */}
{__DEV__ && (
<View
style={{
position: "absolute",
bottom: 0,
height: insets.bottom,
left: 0,
right: 0,
backgroundColor: "rgba(255,0,0,0.3)",
}}
/>
)}
</View>
);
}

第四步:关键 Android 原生适配(针对遗留问题)

android/app/src/main/java/com/yourapp/MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import android.os.Build;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowInsetsController;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Android 15+ 边缘处理
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getWindow().setDecorFitsSystemWindows(false);

final WindowInsetsController insetsController = getWindow().getInsetsController();
if (insetsController != null) {
// 控制导航栏行为 (新API)
insetsController.setSystemBarsBehavior(
WindowInsetsController.BEHAVIOR_DEFAULT
);
}
}
}

兼容性注意事项

方案 Android <14 Android 15+ 备注
基础 SafeAreaView 需升级
EdgeToEdgeWrapper 推荐方案
原生 setDecorFits… ⚠️ 需版本条件检查

结语

在 Android 15 强制推行的Full-Screen App 革命中,主动处理 Insets 不再是可选项。建议:

  1. 立即更新react-native-safe-area-context到最新版
  2. 使用提供的EdgeToEdgeWrapper组件替换旧方案
  3. MainActivity.java中添加未来兼容代码

据 Android 官方统计,Edge-to-Edge 问题在 Android 15 设备上的 Crash 率已飙升320%,及时修复可避免大规模用户流失

问题描述

我突然想把我 Blog 的主页上的排序换一下, 因为一直以来都是按 create_at 排序的, 所以我想换成 update_at, 然后我搜索了一下, 发现有一个配置可以满足这个需求.

就是这个:

1
2
3
4
5
6
7
8
# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
path: ""
per_page: 5
order_by: -updated # 这个地方

然后我修改了这个配置, 本地跑一下 hexo s 嗯. 完美!
然后推送到 CloudFlare 自动部署.

嗯…部署出来, 我的主页顺序是乱的. 并且每次部署的结果都不一致.

Read more »