Skip to content
Go back

用 React 组织移动端页面中的状态与交互

移动端页面做得越深入,越会发现它不是缩小尺寸的 PC 页面。屏幕空间有限,用户使用触摸完成操作,页面内容往往又依赖异步请求:筛选面板、吸顶导航、下拉加载、详情弹层和错误重试经常同时存在。

最近在用 React 整理这类移动端页面时,我越来越倾向于先拆状态,再开始拆组件。因为页面是否容易维护,通常不取决于 JSX 写得多漂亮,而取决于一个交互发生以后,哪些地方应该变化。

页面状态可以先分成三类

一个包含筛选和信息流的移动页面,大致有三种状态:

业务数据状态:列表数据、分页信息、筛选项、详情内容界面展示状态:筛选层是否展开、当前 Tab、骨架屏和空状态交互过程状态:请求是否进行中、是否还有下一页、是否正在提交

如果所有状态都集中到一个大对象里,列表翻页、切换筛选和打开弹层会互相影响。更清晰的方式是让每一类状态拥有明确用途:

class FeedPage extends React.Component {  state = {    list: [],    query: { category: "all", sort: "hot" },    page: 1,    hasMore: true,    loading: false,    filterVisible: false,    activeItem: null  };}

listquery 决定数据展示,filterVisibleactiveItem 决定局部界面,loadinghasMore 控制请求节奏。这种划分并不复杂,但能够减少交互叠加之后的混乱。

筛选变化需要重置列表上下文

移动端列表最常见的问题之一,是筛选条件变化以后仍然沿用旧分页位置。用户已经从“热门”切到“最新”,页面却在新条件下请求第二页,或者新旧列表内容混在一起。

筛选确认时应当显式重置列表状态:

handleFilterConfirm = query => {  this.setState(    {      query,      page: 1,      list: [],      hasMore: true,      filterVisible: false    },    () => this.loadList()  );};

这里并不是仅修改查询参数,而是开启了一次新的列表会话。将这个边界写清楚,后面加入排序、地区或价格条件时,也不会不断补特殊判断。

触底加载要避免重复请求

移动端滚动很快,触底回调可能在短时间内多次触发。如果不保护请求状态,相同页数据可能重复插入列表。

loadMore = () => {  const { loading, hasMore, page } = this.state;  if (loading || !hasMore) return;  this.loadList(page + 1);};loadList = nextPage => {  this.setState({ loading: true });  fetchFeed({ ...this.state.query, page: nextPage })    .then(result => {      this.setState(prevState => ({        list:          nextPage === 1            ? result.items            : prevState.list.concat(result.items),        page: nextPage,        hasMore: result.hasMore      }));    })    .finally(() => {      this.setState({ loading: false });    });};

加载锁、页码和是否结束这三个信息需要放在同一个流程中维护,否则页面可能表现为底部 loading 不消失,或者重复出现相同内容。

弹层与滚动需要一起处理

筛选面板或图片预览出现时,底层列表如果仍能滚动,会让用户关闭弹层后回到意料之外的位置。移动端 Web 页面需要处理背景滚动锁定:

function lockPageScroll() {  document.body.style.overflow = "hidden";}function unlockPageScroll() {  document.body.style.overflow = "";}

实际场景中还要考虑 iOS WebView 的滚动容器和弹层内部滚动区域。重要的是,弹层不能只被看作一个显示状态,它会影响页面的触摸和滚动上下文。

组件复用应围绕稳定交互

移动页面里适合抽出的组件,通常不是最小的一段 DOM,而是边界比较稳定的交互模块:

页面组件负责组织请求和状态关系,局部组件负责交互细节。这样业务新增条件时,修改范围更可控。

移动端页面最终是在管理反馈节奏

React 帮助我们把界面描述成状态的结果,但移动端体验是否可靠,仍然取决于对交互节奏的处理:点击之后有没有即时反馈,请求变慢时是否保留上下文,弹层打开以后页面是否稳定,返回列表时用户是否还能找到刚才的位置。

把数据、展示与交互过程拆开以后,页面并不会少掉复杂度,但复杂度有了归属。这是 React 在移动端业务中最有价值的地方。


Share this post on: