You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何仅针对移动端调用setState({collapse: true})并按窗口大小切换状态?

如何根据屏幕尺寸控制React组件的collapse状态?

这个需求在响应式开发里很常见,我来给你一步步拆解实现方案,不管你用类组件还是函数组件都能搞定:

核心思路

我们需要监听窗口的resize事件,根据当前视口宽度判断是否处于移动端,然后动态更新collapse状态;同时配合条件渲染或CSS媒体查询,实现「移动端隐藏列表、平板及以上隐藏切换按钮」的效果。


方案一:纯React逻辑实现(类组件)

如果你的项目还在用类组件,可以这么写:

class ResponsiveList extends React.Component {
  constructor(props) {
    super(props);
    // 初始化时就判断屏幕尺寸,设置初始collapse状态
    this.state = {
      collapse: window.innerWidth < 768 // 768px作为平板/移动端的分界,可按需调整
    };
    this.handleResize = this.handleResize.bind(this);
  }

  // 组件挂载后添加resize监听
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
  }

  // 组件卸载前移除监听,避免内存泄漏
  componentWillUnmount() {
    window.removeEventListener('resize', this.handleResize);
  }

  // 处理窗口尺寸变化
  handleResize() {
    const isMobile = window.innerWidth < 768;
    // 移动端自动收起列表,平板及以上自动展开
    this.setState({ collapse: isMobile });
  }

  // 手动切换collapse状态(仅移动端可用)
  toggleCollapse = () => {
    this.setState(prevState => ({
      collapse: !prevState.collapse
    }));
  }

  render() {
    const { collapse } = this.state;
    const isMobile = window.innerWidth < 768;

    return (
      <div className="list-wrapper">
        {/* 切换按钮:仅在移动端显示 */}
        {isMobile && (
          <button onClick={this.toggleCollapse} className="toggle-btn">
            {collapse ? '展开列表' : '收起列表'}
          </button>
        )}

        {/* 列表:平板及以上始终显示,移动端根据collapse状态切换 */}
        {!isMobile || !collapse ? (
          <ul className="list-content">
            <li>列表项1</li>
            <li>列表项2</li>
            <li>列表项3</li>
          </ul>
        ) : null}
      </div>
    );
  }
}

方案二:函数组件+Hook实现

如果用的是React Hooks,代码会更简洁:

import React, { useState, useEffect } from 'react';

// 防抖函数:优化resize事件触发频率,避免频繁更新状态
const debounce = (func, delay = 200) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

const ResponsiveList = () => {
  const [collapse, setCollapse] = useState(window.innerWidth < 768);

  const handleResize = debounce(() => {
    const isMobile = window.innerWidth < 768;
    setCollapse(isMobile);
  });

  // 添加/移除resize监听
  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  const toggleCollapse = () => {
    setCollapse(prev => !prev);
  };

  const isMobile = window.innerWidth < 768;

  return (
    <div className="list-wrapper">
      {isMobile && (
        <button onClick={toggleCollapse} className="toggle-btn">
          {collapse ? '展开列表' : '收起列表'}
        </button>
      )}
      {!isMobile || !collapse ? (
        <ul className="list-content">
          <li>列表项1</li>
          <li>列表项2</li>
          <li>列表项3</li>
        </ul>
      ) : null}
    </div>
  );
};

export default ResponsiveList;

方案三:结合CSS媒体查询(推荐)

用CSS媒体查询来控制元素显示隐藏,能减少JS的条件渲染逻辑,更符合响应式开发的最佳实践:

第一步:写CSS样式

/* 平板及以上(≥768px)隐藏切换按钮 */
@media (min-width: 768px) {
  .toggle-btn {
    display: none;
  }
}

/* 移动端(<768px)默认隐藏列表 */
@media (max-width: 767px) {
  .list-content {
    display: none;
  }
  /* 展开状态下显示列表 */
  .list-content.expanded {
    display: block;
  }
}

第二步:React组件逻辑

import React, { useState, useEffect } from 'react';
import './ResponsiveList.css';

const debounce = (func, delay = 200) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

const ResponsiveList = () => {
  const [isExpanded, setIsExpanded] = useState(false);
  const [isMobile, setIsMobile] = useState(window.innerWidth < 768);

  const handleResize = debounce(() => {
    const mobile = window.innerWidth < 768;
    setIsMobile(mobile);
    // 切换到平板及以上时,自动展开列表
    if (!mobile) setIsExpanded(true);
  });

  useEffect(() => {
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  const toggleExpand = () => {
    setIsExpanded(prev => !prev);
  };

  return (
    <div className="list-wrapper">
      <button onClick={toggleExpand} className="toggle-btn">
        {isExpanded ? '收起列表' : '展开列表'}
      </button>
      <ul className={`list-content ${isExpanded ? 'expanded' : ''}`}>
        <li>列表项1</li>
        <li>列表项2</li>
        <li>列表项3</li>
      </ul>
    </div>
  );
};

export default ResponsiveList;

关键注意点

  1. 断点选择:我用了768px作为平板和移动端的分界,你可以根据自己的设计需求调整(比如992px、1200px等)。
  2. 性能优化:一定要给resize事件加防抖,不然窗口拖动时会频繁触发setState,影响性能。
  3. 内存泄漏:组件卸载时一定要移除resize监听,避免内存泄漏问题。

内容的提问来源于stack exchange,提问作者Sushmit Sagar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:12:18