useSelector 和 useEffect 重新渲染优化
useSelector and useEffect rerender optimization
我有 table 组件,其中 table 行存储在 useState 中。
此外,我在 table 组件之外还有搜索器组件。
当搜索器中的数据发生变化时,tableuseEffect 中的行会更新。
效果很好,但会导致两次重新渲染。我明白为什么。第一次重新渲染是因为 useSelector,第二次是因为 useEffect 有 useSelector 值作为依赖项。
但是如何避免一次重新渲染。我希望它在 table 行更改时重新呈现,但在搜索器更改时不重新呈现。
const CatalogTable: React.FC<CatalogTableProps> = ({rows}) => {
const [tableRows, setTableRows] = React.useState(rows)
const searcher = useSelector(getTableSearcher, shallowEqual)
const getData = async () => {
const {data} = await CatalogService.getAllCatalogProducts({page: 1, searcher: searcher})
setTableRows(data.products)
}
React.useEffect(() => {
if(searcher)
getData()
}, [searcher])
return (
<>
<div className={styles.defaultTable}>
<Table
headers={headers}
label="Products catalog"
rows={tableRows}
total={total}
pagination
addButton
editButtons
searcher
getPage={(page: number) => nextPage(page)}
type='catalog'
/>
</div>
</>
)
}
export default CatalogTable
可能的解决方案之一是记忆:
const CatalogTable: React.FC<CatalogTableProps> = ({rows}) => {
const [tableRows, setTableRows] = React.useState(rows)
const searcher = useSelector(getTableSearcher, shallowEqual)
const getData = async () => {
const {data} = await CatalogService.getAllCatalogProducts({page: 1, searcher: searcher})
setTableRows(data.products)
}
React.useEffect(() => {
if(searcher)
getData()
}, [searcher])
const result = useMemo( () =>
<>
<div className={styles.defaultTable}>
<Table
headers={headers}
label="Products catalog"
rows={tableRows}
total={total}
pagination
addButton
editButtons
searcher
getPage={(page: number) => nextPage(page)}
type='catalog'
/>
</div>
</>, [tableRows]
);
return result;
}
export default CatalogTable
另一种解决方案是将 tableRows 和搜索查询都放在 redux 存储中,并通过异步中间件同时更新它们。
它重新呈现是因为您的状态正在改变,这是预期的结果。这是因为tableRows是在useEffect里面设置的(效果里面有一个setTableRows,这个要看搜索者)。
不确定该组件是如何使用的,因为您在 props 中传递了一些初始行并重置了组件内的行 (setTableRows),但是从您的评论看来您并不真正关心搜索者。完成您想要的解决方案是将行作为道具传递并从组件中删除状态,这样您的组件将只关心行而不关心搜索者。
无论如何,优化重新渲染并不是最好的方法,除非你的渲染很慢。此外,在 useEffect 中定义异步调用更安全,这样更容易确保所有需要的依赖项都在 dependencies 数组中。
我有 table 组件,其中 table 行存储在 useState 中。
此外,我在 table 组件之外还有搜索器组件。
当搜索器中的数据发生变化时,tableuseEffect 中的行会更新。
效果很好,但会导致两次重新渲染。我明白为什么。第一次重新渲染是因为 useSelector,第二次是因为 useEffect 有 useSelector 值作为依赖项。
但是如何避免一次重新渲染。我希望它在 table 行更改时重新呈现,但在搜索器更改时不重新呈现。
const CatalogTable: React.FC<CatalogTableProps> = ({rows}) => {
const [tableRows, setTableRows] = React.useState(rows)
const searcher = useSelector(getTableSearcher, shallowEqual)
const getData = async () => {
const {data} = await CatalogService.getAllCatalogProducts({page: 1, searcher: searcher})
setTableRows(data.products)
}
React.useEffect(() => {
if(searcher)
getData()
}, [searcher])
return (
<>
<div className={styles.defaultTable}>
<Table
headers={headers}
label="Products catalog"
rows={tableRows}
total={total}
pagination
addButton
editButtons
searcher
getPage={(page: number) => nextPage(page)}
type='catalog'
/>
</div>
</>
)
}
export default CatalogTable
可能的解决方案之一是记忆:
const CatalogTable: React.FC<CatalogTableProps> = ({rows}) => {
const [tableRows, setTableRows] = React.useState(rows)
const searcher = useSelector(getTableSearcher, shallowEqual)
const getData = async () => {
const {data} = await CatalogService.getAllCatalogProducts({page: 1, searcher: searcher})
setTableRows(data.products)
}
React.useEffect(() => {
if(searcher)
getData()
}, [searcher])
const result = useMemo( () =>
<>
<div className={styles.defaultTable}>
<Table
headers={headers}
label="Products catalog"
rows={tableRows}
total={total}
pagination
addButton
editButtons
searcher
getPage={(page: number) => nextPage(page)}
type='catalog'
/>
</div>
</>, [tableRows]
);
return result;
}
export default CatalogTable
另一种解决方案是将 tableRows 和搜索查询都放在 redux 存储中,并通过异步中间件同时更新它们。
它重新呈现是因为您的状态正在改变,这是预期的结果。这是因为tableRows是在useEffect里面设置的(效果里面有一个setTableRows,这个要看搜索者)。
不确定该组件是如何使用的,因为您在 props 中传递了一些初始行并重置了组件内的行 (setTableRows),但是从您的评论看来您并不真正关心搜索者。完成您想要的解决方案是将行作为道具传递并从组件中删除状态,这样您的组件将只关心行而不关心搜索者。
无论如何,优化重新渲染并不是最好的方法,除非你的渲染很慢。此外,在 useEffect 中定义异步调用更安全,这样更容易确保所有需要的依赖项都在 dependencies 数组中。