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;
关键注意点
- 断点选择:我用了768px作为平板和移动端的分界,你可以根据自己的设计需求调整(比如992px、1200px等)。
- 性能优化:一定要给
resize事件加防抖,不然窗口拖动时会频繁触发setState,影响性能。 - 内存泄漏:组件卸载时一定要移除
resize监听,避免内存泄漏问题。
内容的提问来源于stack exchange,提问作者Sushmit Sagar
相关产品推荐
相关产品推荐

