简体   繁体   English

如果 props 改变,React.memo 不会重新渲染

[英]React.memo not re render if props change

I'm trying to create a Table component from scratch using React memo component as rows to prevent unecessary re-rendering.我正在尝试使用 React memo 组件作为行从头开始创建一个 Table 组件,以防止不必要的重新渲染。 The rows cells is an array of React components created from a children function with row data, row id, row index and a commitChange function as parameters.行单元格是从子函数创建的 React 组件数组,其中包含行数据、行 ID、行索引和 commitChange 函数作为参数。 The commitChange function is used to set the Table state from a row. commitChange 函数用于从一行设置表状态。 This is the code:这是代码:

<Table data={[{name: 1}, {name: 2}]}>
            {({data, index, id, commitChange})=>
                [
                <div>Name: {data.name}</div>,
                <TextBox value={data.name} onChange={(value)=>commitChange('name', parseInt(value, 10))}/>,
                <TextBox value={data.place}/>
                ]
            }
 </Table>

TableComponents.jsx TableComponents.jsx

export const Table = ({ data: initialData, maxRows = 10, children: makeChildren, primaryKey = 'ID' }) => {
const [TableData, setTableData] = useState(initialData);
console.log('table re-render')

useEffect(() => {
    console.log('--->table data', TableData)
}, [TableData]);

useEffect(() => {
    setTableData(initialData)
}, [initialData]);

const renderCells = useCallback((param) => {
    return makeChildren(param)
}, [])

const commitChange = useCallback((field, value, index) => {
    setTableData(prevTableData => {
        const newState = Array.from(prevTableData)
        newState[index][field] = value
        return [...newState]
    })
}, [])

const renderRows = () => {
    return TableData.map((row, i) =>
        <TableRow
            key={row[primaryKey]}
            index={i}
            rowData={row}
            cells={renderCells}
            id={row[primaryKey]}
            updateTableData={commitChange}
        />
    )
}

//
return (
    <table>
        <tbody>
            {
                renderRows()
            }
        </tbody>
    </table>
  );
}

const TableRow = React.memo(({ index, rowData, cells, id, updateTableData }) => {

console.log('render row' + index, rowData)

useEffect(() => {
    console.log('row ' + index + ' data', rowData)
}, [rowData])


const renderCells = () => {
    return cells({ data: rowData, index, id, commitChange: (field, value) => updateTableData(field, value, index) }).map((c, i) => {
        return (
            <td key={i}>
                {c}
            </td>
        )
    })
}

return (
    <tr>
        {renderCells()}
    </tr>
)
})

When an element was added to the data props on the Table component the table re-render and render only the added row and this works ok.当一个元素被添加到 Table 组件上的数据道具时,表格会重新渲染并只渲染添加的行,这可以正常工作。

But when a row element is edit from the textbox in the second cell the data on the parent Table component was correctly updated but the row not re-render.但是,当从第二个单元格中的文本框中编辑行元素时,父表组件上的数据已正确更新,但该行不会重新呈现。 When I check the previus and next proprieties passed to component with React.memo areEqual function ( Documentation here ) the data proprieties is the same.当我使用 React.memo areEqual 函数(此处文档)检查传递给组件的上一个和下一个属性时,数据属性是相同的。 The table component is re-render when TableData is update by row and the renderRows function is executed but without re-render of the updated row.当 TableData 按行更新时重新渲染表格组件,并且执行了 renderRows 函数,但不会重新渲染更新的行。

What is the problem?问题是什么? Thanks for help感谢帮助

PS No I don't want an external library to make custom Table elements PS 不,我不想要外部库来制作自定义表格元素

The problem is that you are shallow-copying your TableData (using ... ) so when you update the value here:问题是您正在浅复制您的 TableData (使用... ),因此当您在此处更新值时:

newState[index][field] = value

... you are mutating the item in the array but the reference to that item stays the same. ...你是变异的项目在数组中,但参照该项目保持不变。 One fix would be to do this:一种解决方法是这样做:

setTableData(prevTableData =>
    prevTableData.map((item, i) =>
      i === index ? { ...item, [field]: value } : item,
    ),
  )

So now a new object is created when a field is updated.因此,现在更新字段时会创建一个新对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM