Polaris IndexTable动态数据更新问题求助
问题:Polaris IndexTable无法动态更新内容
我是Polaris/Shopify新手,使用<IndexTable />组件创建店铺优惠列表,已配置promotedBulkActions,API调用正常,但无法实现内容动态更新——删除条目后对应行未消失,切换状态后状态未自动变更。数据来自自定义API接口,解析后存入rowMarkup变量,知道需结合useState实现,但不清楚最后一步操作。
当前代码(已移除无关内容):
import { Card, IndexTable, useIndexResourceState, Filters, TextField } from "@shopify/polaris"; import { useAppQuery, useAuthenticatedFetch } from "../hooks"; import { useState, useCallback } from 'react'; import { useEffect, useLayoutEffect } from "react"; import { TitleBar, useNavigate } from "@shopify/app-bridge-react"; import { data } from "@shopify/app-bridge/actions/Modal"; export function OfferTabs() { const [offers, setOffers] = useState([]); const [taggedWith, setTaggedWith] = useState('current'); const [offerList, setOfferList] = useState([]); const [selected, setSelected] = useState(0); const [active, setActive] = useState(false); const [statusText, setStatusText] = useState('Active'); const [status, setStatus] = useState(1); const navigate = useNavigate(); useLayoutEffect(() => { fetch("xxxxx") .then(res => res.json()) .then(result => { setOffers(result); }); }, []); // const fetch = useAuthenticatedFetch(); const getStatusText = (status) => { const _t = (status === 1) ? 'Active' : 'Inactive'; // setStatus(_t); return _t; } const getContent = (type) => { let _return = []; Object.keys(offers).map(o => { offers[o].map(m => { _return.push( { id: m.id, name: m.name, type: m.type, start_date: m.start_date, end_date: m.end_date, status: m.status, status_text: getStatusText(m.status), shopify_id: m.shopify_id, offer_type: o } ); }); }); return _return; } /* handling functions */ const handleDelete = () => { const _itemCount = selectedResources.length; const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items` if (confirm(`Do you want to delete ${_qtyStr}? This cannot be undone!`)) { const _queryData = selectedResources.join(","); const _queryURL = `xxxx`; const _headers = {'method':'DELETE'} /* send the request and remove the elements from the DOM */ fetch(_queryURL,_headers) .then(()=> { console.log("TO DO: Auto-refresh the content"); }); } } const handleStatusChange = (v) => { const _itemCount = selectedResources.length; const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items` if (confirm(`Do you want to change the status of ${_qtyStr}?`)) { const _queryData = selectedResources.join(","); const _queryURL = `https://xxxxx`; const _headers = { 'method': 'PUT' } fetch(_queryURL,_headers) .then(()=> { console.log("TO DO: Auto-refresh the content"); }); } } /* this will convert the offers data into the correct format for an IndexTable */ const indexContent = getContent(); const resourceName = { singular: 'promotion', plural: 'promotions', }; const { selectedResources, allResourcesSelected, handleSelectionChange } = useIndexResourceState(indexContent); const rowMarkup = indexContent.map( ({ id, name, type, start_date, end_date, status, status_text, offer_type }, index) => ( <IndexTable.Row id={id} key={id} selected={selectedResources.includes(id)} position={index} > <IndexTable.Cell>{name}</IndexTable.Cell> <IndexTable.Cell>{type}</IndexTable.Cell> <IndexTable.Cell>{start_date}</IndexTable.Cell> <IndexTable.Cell>{end_date}</IndexTable.Cell> <IndexTable.Cell>{offer_type}</IndexTable.Cell> <IndexTable.Cell>{status_text}</IndexTable.Cell> </IndexTable.Row> ), ); const promotedBulkActions = [ { title: "Change Status", actions: [ { content: 'Activate', onAction: () => handleStatusChange(1) }, { content: 'Deactivate', onAction: () => handleStatusChange(0) } ] }, { title: "Other Actions", actions: [ { content: 'Delete', onAction: handleDelete } ] } ]; return ( <Card> <IndexTable resourceName={resourceName} itemCount={indexContent.length} selectedItemsCount={ allResourcesSelected ? 'All' : selectedResources.length } onSelectionChange={handleSelectionChange} promotedBulkActions={promotedBulkActions} headings={[ { title: 'Name' }, { title: 'Type' }, { title: 'Start Date' }, { title: 'End Date' }, { title: 'Schedule' }, { title: 'Status' } ]} > {rowMarkup} </IndexTable> </Card> ) }
操作步骤
- 选中某一行
- 执行“Activate”操作
预期结果
选中的行状态更新
实际结果
API调用成功,但行内容未更新
解决方案
核心是更新React状态offers,因为rowMarkup依赖offers生成,状态变更会触发组件重新渲染,自动更新表格内容。具体修改如下:
1. 封装数据获取函数
把初始加载的请求封装成可复用函数,方便操作后重新拉取最新数据:
const fetch = useAuthenticatedFetch(); // 取消注释,使用Shopify认证请求 const fetchOffers = useCallback(() => { fetch("xxxxx") .then(res => res.json()) .then(result => { setOffers(result); }); }, [fetch]); // 初始加载调用 useLayoutEffect(() => { fetchOffers(); }, [fetchOffers]);
2. 修改删除操作,更新状态
删除请求成功后,调用fetchOffers重新拉取数据:
const handleDelete = () => { const _itemCount = selectedResources.length; const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items`; if (confirm(`Do you want to delete ${_qtyStr}?\nThis cannot be undone!`)) { const _queryData = selectedResources.join(","); const _queryURL = `xxxx`; const _options = { method: 'DELETE' }; fetch(_queryURL, _options) .then(() => { fetchOffers(); // 重新拉取最新数据,触发表格更新 }); } }
3. 修改状态切换操作,更新状态
状态修改请求成功后同样重新拉取数据:
const handleStatusChange = (v) => { const _itemCount = selectedResources.length; const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items`; if (confirm(`Do you want to change the status of ${_qtyStr}?`)) { const _queryData = selectedResources.join(","); const _queryURL = `https://xxxxx`; const _options = { method: 'PUT' }; fetch(_queryURL, _options) .then(() => { fetchOffers(); // 重新拉取最新数据,触发表格更新 }); } }
4. 确保选中状态同步
useIndexResourceState依赖indexContent,每次offers更新时会自动重新计算选中状态,无需额外修改,确保组件渲染时该逻辑能获取最新的indexContent即可。
内容的提问来源于stack exchange,提问作者Anthony Earles
相关产品推荐
相关产品推荐

