Reputation: 586
I have a react table as follow:
I have a table in each of the tab shown below (EN, CN, VN, TH). Currently, when I try to input text in the "messages" column (3rd column in the table below), the table will re-render each time I input an alphabet. The cursor will lose focus and I would have to manually click on the input box again to continue typing.
table.js
const [playerNotification, setPlayerNotification] = React.useState([
{
'language': 'vn',
'notificationDetails': [
{
'key': 'event',
'description': 'test event',
'message': ''
},
{
'key': 'event 2',
'description': 'test event 2',
'message': ''
},
{
'key': 'event 3',
'description': 'test event 3',
'message': ''
}
]
},
{
'language': 'cn',
'notificationDetails': [
{
'key': 'event',
'description': 'test event',
'message': ''
},
{
'key': 'event 2',
'description': 'test event 2',
'message': ''
},
{
'key': 'event 3',
'description': 'test event 3',
'message': ''
}
]
}];
const updateMessage = (e, value, index, notificationDetailsIndex) => {
let copyData = playerNotification.slice();
let copy = copyData[index];
let copyDetails = copy.notificationDetails[notificationDetailsIndex];
copyDetails.message = value;
copy.notificationDetails[notificationDetailsIndex] = copyDetails;
copyData[index] = copy;
setPlayerNotification(copyData);
}
This is my table code:
<div className={classes.tabsRoot}>
<AppBar position="static" color="default">
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
>
<Tab label="EN" {...a11yProps(0)} />
<Tab label="CN" {...a11yProps(1)} />
<Tab label="VN" {...a11yProps(2)} />
<Tab label="TH" {...a11yProps(3)} />
</Tabs>
</AppBar>
{playerNotification.map((p, index) => {
return (
<TabPanel value={value} index={index}>
<Table key={index} aria-label="simple table">
<TableHead style={customColumnStyle} className={classes.header}>
<TableRow key={"header" + p.language}>
<TableCell className={classes.customBorderRightStyle}>
Event Trigger Key
</TableCell>
<TableCell className={classes.customBorderRightStyle}>
Description
</TableCell>
<TableCell className={classes.customBorderRightStyle}>
Messages
</TableCell>
</TableRow>
</TableHead>
<TableBody style={customColumnStyle}>
{p.notificationDetails.map((notification, notificationIndex) => {
return (
<Fragment>
<TableRow key={p.language + notificationIndex}>
<TableCell
style={{ backgroundColor: "rgba(0, 0, 0, 0.05)" }}
>
{notification.key}
</TableCell>
<TableCell
style={{ backgroundColor: "rgba(0, 0, 0, 0.05)" }}
>
{notification.description}
</TableCell>
<TableCell>
<input
type="text"
key={p.language + notification.key + notificationIndex}
className={classes.customInputStyle}
onChange={(e) =>
updateMessage(
e,
e.target.value,
index,
notificationIndex
)
}
value={notification.message}
/>
</TableCell>
{/* <TableCell>{messageComponent(index, notificationIndex, notification)}</TableCell> */}
</TableRow>
</Fragment>
);
})}
</TableBody>
</Table>
</TabPanel>
);
})}
</div>
I've tried adding a unique key to each table row but the behavior remains the same - my cursor keeps losing focus. Adding autofocus makes the cursor jump to the third line when I enter an alphabet. Here's the link I've tried React.js - input losing focus when rerendering.
I believe the possible cause might be cause I'm looping the table each time I input an alphabet? Would really appreciate your help to point out the problem in my table code and how I can go about fixing it. Thanks!
Upvotes: 3
Views: 3120
Reputation: 161
I have a solution for this as long as you have an unique key for each cell that can be modified.
Create either a useState variable or useRef (ideally) variable that holds the current key of the cell you want to keep focus. Then you modify this variable to the current cell's key to be focuse on the onChange function. Then you will use the autoFocus attribute conditionally if the current cell key matches the focused variable reference:
let editableKeyToFocus = useRef(null);
const key = getUniqueKey();
return (
<TextField
key={key}
onChange={(e) => {
editableKeyToFocus.current = key;
onChangeFunctionToCall()
}
autoFocus={key === editableKeyToFocus.current}
/>
)
In other words you will manually keep the reference to which cell you want to keep focus everytime you call onChange.
Upvotes: 7