Reputation: 3885
Explanation
Because my table is being created / mapped by my data
state hook and because my "handleAccountTypeOnChange" function modifies data
, that function will always cause my TableRow component to re-render because it is modifying data
. so using useCallback
wouldn't work in this scenario because of it's dependency on data
.
How can I fix this? I can restructure my table state in any way, flatten it more maybe. But I still don't understand how I can solve this without passing in some sort of function that modifies the main data that wouldn't cause all the rows to render. Is the only way to solve this is to use redux? Would love to know how to accomplish this without it.
EDIT
made a codepen. Slightly different because no libraries but same concept. https://codepen.io/daletron3030/pen/PoZqLOx
Code
i get data from my backend and i set it into my data. for the sake of simplicity, my data looks like this:
App Component
const App = () => {
const [data, setData] = React.useState([
{
username: "someUserName1",
accountType: "admin",
},
{
username: "someUserName2",
accountType: "normal",
}, // etc
]);
const handleAccountTypeOnChange = (e, {name, value}) => {
const index = data.findIndex(account => account.username === name);
setData(update(data, {[index]: {accountType: {$set: value}}}));
};
return (
<>
<Table>
<Table.Body>
{
data.map((user, index) => (
<TableRow
key={index}
handleAccountTypeOnChange={handleAccountTypeOnChange}
username={user.username}
/>
))
}
</Table.Body>
</Table>
</>
)
TableRow Component
const TableRow = React.memo(({ handleAccountTypeOnChange, username }) => {
const accountTypeOptions = [
{ key: "admin", value: "admin", text: "Administrator" },
{ key: "normal", value: "normal", text: "Normal" }
];
return (
<>
<Table.Row>
<Table.Cell>
<Dropdown
name={username}
onChange={handleAccountTypeOnChange}
options={accountTypeOptions}
selection
value={accountType}
/>
</Table.Cell>
<Table.Cell>{username}</Table.Cell>
</Table.Row>
</>
)});
export default TableRow;
Upvotes: 1
Views: 950
Reputation: 44900
If you use a functional update with your setData
call, then the function never needs to change and it can be memoized with useCallback
:
const handleAccountTypeOnChange = React.useCallback(
(e, {name, value}) => {
setData(prevData => {
const index = prevData.findIndex(account => account.username === name);
setData(update(prevData, {[index]: {accountType: {$set: value}}}));
})
},
[]
);
This useCallback
does not need to list setData
as a dependency because the callbacks returned from useState
do not change over time.
Upvotes: 1