组件不在状态更改时呈现
Component not rendering on state change
我有一个包含 react-table 和按钮的组件。它应该以空 table 开头,用户单击按钮添加一行并输入数据。
import React from "react";
import {Button, Row} from "react-bootstrap";
import {useTable} from "react-table";
export default function PlantDetail() {
const [plants, setPlants] = React.useState([])
const data = React.useMemo(() => plants, [plants])
const addRow = () => {
plants.push({"species_id": "10002", "name": "Maria", "weight": 15})
setPlants(plants)
}
const columns = React.useMemo(
() => [
{
Header: "Name", accessor: "name",
},
{Header: "Weight", accessor: "weight"},
],
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({columns, data})
return (<React.Fragment>
<Row>
<table {...getTableProps()}>
<thead>
{
headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{
headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{
rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</Row>
<Row>
<Button onClick={addRow}>Button</Button>
</Row>
</React.Fragment>)
}
所以我只专注于创建一个新行,这就是为什么在这个例子中我只是添加一个硬编码值。
但是按钮不会导致渲染。添加了数据,但没有进行渲染。
我在这里错过了什么?
您正在使用 push
改变状态。
这会导致“错过”状态更新而不是重新渲染。当您的状态是对象或数组时,您需要在更新时传递一个新实例。
下面是 React 如何确定是否应该更新的简化示例:
const state = [1,2];
function setState(newState) {
if (state !== newState) {
console.log('re-render');
} else {
console.log('skip');
}
}
// Wrong
state.push(3);
setState(state);
// Right
setState(state.concat(4));
有多种解决方案,但其中一种是 concat
。
setPlants(plants.concat({"species_id": "10002", "name": "Maria", "weight": 15}))
这会起作用,因为 concat
不会改变原始数组,而是 returns 一个新数组。
这是一个差异示例:
const arr1 = [1,2,3];
const arr2 = [1,2,3];
arr1.push(4);
console.log('arr1', arr1);
const arr3 = arr2.concat(4);
console.log('arr2', arr2);
console.log('arr3', arr3);
我有一个包含 react-table 和按钮的组件。它应该以空 table 开头,用户单击按钮添加一行并输入数据。
import React from "react";
import {Button, Row} from "react-bootstrap";
import {useTable} from "react-table";
export default function PlantDetail() {
const [plants, setPlants] = React.useState([])
const data = React.useMemo(() => plants, [plants])
const addRow = () => {
plants.push({"species_id": "10002", "name": "Maria", "weight": 15})
setPlants(plants)
}
const columns = React.useMemo(
() => [
{
Header: "Name", accessor: "name",
},
{Header: "Weight", accessor: "weight"},
],
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({columns, data})
return (<React.Fragment>
<Row>
<table {...getTableProps()}>
<thead>
{
headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{
headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{
rows.map(row => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>
{cell.render('Cell')}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
</Row>
<Row>
<Button onClick={addRow}>Button</Button>
</Row>
</React.Fragment>)
}
所以我只专注于创建一个新行,这就是为什么在这个例子中我只是添加一个硬编码值。
但是按钮不会导致渲染。添加了数据,但没有进行渲染。
我在这里错过了什么?
您正在使用 push
改变状态。
这会导致“错过”状态更新而不是重新渲染。当您的状态是对象或数组时,您需要在更新时传递一个新实例。
下面是 React 如何确定是否应该更新的简化示例:
const state = [1,2];
function setState(newState) {
if (state !== newState) {
console.log('re-render');
} else {
console.log('skip');
}
}
// Wrong
state.push(3);
setState(state);
// Right
setState(state.concat(4));
有多种解决方案,但其中一种是 concat
。
setPlants(plants.concat({"species_id": "10002", "name": "Maria", "weight": 15}))
这会起作用,因为 concat
不会改变原始数组,而是 returns 一个新数组。
这是一个差异示例:
const arr1 = [1,2,3];
const arr2 = [1,2,3];
arr1.push(4);
console.log('arr1', arr1);
const arr3 = arr2.concat(4);
console.log('arr2', arr2);
console.log('arr3', arr3);