React应用移动端视图数据已获取但不渲染问题求助
React应用移动端无法渲染内容的排查与解决
问题现象
桌面浏览器可正常展示数据,但切换至移动端视图(浏览器调试工具或真实手机)时,API已成功获取数据,但页面无法渲染内容。
核心问题排查
1. API响应结构的设备差异
两处组件均使用page_type=DESKTOP_WEB_LISTING请求API,Swiggy的API会根据该参数返回不同结构的卡片数据。移动端下卡片索引位置发生变化,导致通过固定索引cards[0]/cards[1]无法获取到目标数据。
2. 固定边距导致内容溢出
Dishes组件中图片容器使用了ml-32 mr-32的固定大边距,移动端屏幕宽度有限,该边距会挤压容器宽度,导致内容被挤出可视区域。
3. 响应式布局缺失
Body组件的筛选栏未做移动端适配,搜索框与按钮会出现挤压;餐厅卡片容器也无移动端边距处理,可能导致内容排版错乱。
解决方案
1. 适配API的设备响应结构
动态切换API的page_type参数,并通过遍历卡片而非固定索引获取数据,提升兼容性:
Body.js 修改fetchData函数
const fetchData = async () => { const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const pageType = isMobile ? "MOBILE_WEB_LISTING" : "DESKTOP_WEB_LISTING"; const data = await fetch(`https://www.swiggy.com/dapi/restaurants/list/v5?lat=18.9777315&lng=72.8273249&is-seo-homepage-enabled=true&page_type=${pageType}`); const json = await data.json(); // 动态查找餐厅数据卡片 const restaurantCard = json?.data?.cards.find(card => card?.card?.card?.gridElements?.infoWithStyle?.restaurants); // 动态查找标题卡片 const titleCard = json?.data?.cards.find(card => card?.card?.card?.header?.title); setTitle(titleCard?.card?.card?.header?.title || "热门餐厅"); const restaurants = restaurantCard?.card?.card?.gridElements?.infoWithStyle?.restaurants || []; setListOfRestaurant(restaurants); setFilteredRestaurant(restaurants); }
Dishes.js 修改fetchData函数
const fetchData = async () => { try { const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); const pageType = isMobile ? "MOBILE_WEB_LISTING" : "DESKTOP_WEB_LISTING"; const data = await fetch(`https://www.swiggy.com/dapi/restaurants/list/v5?lat=18.9777315&lng=72.8273249&is-seo-homepage-enabled=true&page_type=${pageType}`); const json = await data.json(); // 动态查找菜品图片卡片 const dishCard = json?.data?.cards.find(card => card?.card?.card?.imageGridCards?.info); setTitle(dishCard?.card?.card?.header?.title || "热门菜品"); setDish(dishCard?.card?.card?.imageGridCards?.info || []); } catch (error) { console.error('数据获取失败:', error); } };
2. 调整Dishes组件的响应式样式
移除固定大边距,改用响应式边距和尺寸:
// 修改标题区域边距 <div className='flex justify-between px-4'> <span className='font-bold text-xl sm:text-2xl'>{title}</span> <div className='flex text-xl sm:text-2xl'> <span onClick={scrollPrev} className='flex items-center justify-center w-8 p-1 h-8 mr-2 cursor-pointer bg-green-300 rounded-full'><GrFormPrevious /></span> <span onClick={scrollNext} className='flex items-center justify-center w-8 p-1 h-8 cursor-pointer bg-green-300 rounded-full'><GrFormNext /></span> </div> </div> // 修改图片容器样式 {dish.length > 0 ? ( <div className="flex justify-start overflow-x-auto gap-4 px-4 mt-3 hide-scrollbar" ref={containerRef}> {dish.map(({ imageId }) => ( <img key={imageId} className="w-[120px] sm:w-[144px] h-[150px] sm:h-[180px] m-auto" src={imageId ? `${CDN_URL}${imageId}` : DEFAULT_FOOD_IMAGE_URL} alt="dish-image" /> ))} </div> ) : ( <div className="px-4 py-8 text-center">暂无热门菜品</div> )}
3. 为Body组件添加响应式布局
调整筛选栏和餐厅卡片容器的样式:
// 修改筛选栏布局 <div className="filter flex flex-wrap justify-center"> <div className="searchBar m-2 p-2 w-full sm:w-auto"> <input data-testid="searchInput" type="text" className="border border-solid py-1 pl-1 border-pink-100 rounded-sm" placeholder="搜索.." value={searchInput} onChange={(e) => { setSearchInput(e.target.value) }} /> <button name="Search" className="px-4 py-1 m-2 bg-pink-100 rounded-lg" onClick={() => { const filteredRestaurant = listOfRestaurants.filter(rest => rest.info.name.toLowerCase().includes(searchInput.toLowerCase())); setFilteredRestaurant(filteredRestaurant) }}>Search</button> </div> <div className="searchBar p-2 flex items-center w-full sm:w-auto justify-center"> <button className="px-4 py-1 bg-gray-100 rounded-lg" onClick={() => { const filteredList = listOfRestaurants.filter((res) => res.info.avgRating > 4.5); setFilteredRestaurant(filteredList) }}>Top Rated Restaurants</button> </div> </div> // 修改餐厅卡片容器边距 <div className="flex flex-wrap px-4"> {filteredRestaurant ? ( filteredRestaurant.map((restaurant) => ( <Link key={restaurant?.info?.id} to={'/restaurants/' + restaurant?.info?.id}> {restaurant.info.avgRating > 4.5 ? ( <RestaurantCardBestSeller resData={restaurant} /> ) : ( <RestaurantCard resData={restaurant} /> )} </Link> )) ) : null} </div>
内容的提问来源于stack exchange,提问作者Ansari Sadaan
相关产品推荐
相关产品推荐

