javascript - 支持可变数据的 React 表库 ( useRef )
问题描述
基本上我正在寻找可以将可变对象(具体是 useRef 对象)作为要显示的主要数据源的反应表库。
基本上我想做这样的事情:
const TableViewComponent = () =>{
const tableData = useRef([{ rowName: 'test', value:0}] -> basically an array of objects that represents data for every row (the structure doesnt matter)
# code that receives data from server and updates the tableData.current with the data needed
return(
<Table data={tableData.current}/>
)
}
基本上,由于我从服务器收到一堆消息并且我不断更新数据(行数保持不变),我不想每次都重新渲染表格。所以我想使用 useRef 来更改表格上显示的数据,而不会触发反应的重新渲染。
我不确定它是否可以完成,但感谢任何帮助:)。我尝试了 react-table、rc-table 但它们似乎没有用。
解决方案
Basically, it looks to me like you'll have to do it yourself.
There's some libraries that might help you (like useTable
which focuses on headless components) but I don't think they offer what you're looking for.
So let's quickly do a mock-up! (note: this is a quick sketch, assume that the undefined variables are stored somewhere else or are given from the fetch)
function useTableData({ initialData, itemsPerPage, ...etc }) {
const data = useRef(initialData);
const [loading, setLoading] = useState(false);
useEffect(() => {
data.current = fetchFromSomeWhere(...etc);
() => (data.current = null);
}, [etc /* Place other dependencies that invalidate out data here*/]);
const handleNewPage = useCallback(
async ({ pageIndex }) => {
if (!data.current[pageIndex * itemsPerPage]) {
setLoading(true);
data.current = [...data.current, await fetchMoreData(pageIndex)];
}
setLoading(false);
return data.current;
},
[itemsPerPage, data, setLoading],
);
return [data, handleNewPage, loading];
}
Notice how every single thing returned from this hook is a constant reference except for the loading! Meaning, that we can safely pass this to a memoized table, and it won't trigger any re-renders.
const TableContainer = memo(etc => {
const [data, handleNewPage, loading] = useDataForTable(...etc);
return (
<>
{loading && <Spinner />}
{/* Look ma, no expensive-renders! */}
<Body {...{ data }} />
<Pagination {...{ handleNewPage }} />
<OtherActions />
</>
);
});
However, you might have noticed that the body won't re-render when we click on the next page! Which was the whole point of pagination! So now we need some sort of state that'll force the Body to re-render
const TableContainer = memo(etc => {
const [currentPage, setPage] = useState(0);
const [data, handleNewPage, loading] = useDataForTable(...etc);
return (
<>
{loading && <Spinner />}
{/* We're still re-rendering here :( */}
<Body {...{ data, currentPage }} />
<Footer {...{ handleNewPage, setPage }} />
<OtherActions />
</>
);
});
And so we're left with a table that to use properly we need to:
- Exercise restraint and properly invalidate old data. Otherwise, we'd be displaying incorrect data.
- 'Unpack' the data from the current ref on the
Body
component, and then render it.
In essence, after all that work we're still left with a solution isn't particularly attractive, unless you have some really complicated actions or some expensive scaffolding around the TableComponent itself. This might however be your case.
推荐阅读
- javascript - 我们如何能够在 javascript 中创建这样的变量?
- python - 理解列表和新文件
- python - 我在构造函数中遇到关键错误,我不知道为什么?
- iis - 获取 HTTP 错误 400 - 标头太长错误
- python - 没有要从文件中解析的列 (EmptyDataError: )
- maven - Kotlin、Spring-boot 和 Maven:未解决的参考:SpringBootApplication
- julia - 了解 Julia Lang 中的 JuMP?
- r - 使用 dplyr mutate 自动生成新变量名的奇怪事情
- c# - Entity Framework Core 在同一个事务中使用具有不同连接字符串的多个上下文
- javascript - 什么时候可以将函数分配给 var?