I am currently working with a scenario where data is being displayed within different div elements, and I wish to enable the selection/focus of a specific div when users use the up/down arrow keys.
While trying to achieve this functionality by using refs and ForwardRefs for child components in TypeScript code, I am facing some challenges. As I am relatively new to React, any suggestions or improvements on the provided code would be greatly appreciated.
Below are snippets of the code:
Option.ts
export interface Option {
id: number;
label: string;
value: string;
}
App.tsx
import React, { useRef, useEffect } from 'react';
import { Option } from './option';
import Options from './options';
export default function App() {
const options: Option[] = [
{ id: 0, label: "Option 1", value: "12000" },
{ id: 1, label: "Option 2", value: "10000" },
{ id: 2, label: "Option 3", value: "11000" },
{ id: 3, label: "Option 4", value: "23000" }
];
const [invTheme, setInvTheme] = React.useState("10000");
const firstRef = React.createRef<HTMLDivElement>();
const checkedRef = React.createRef<HTMLDivElement>();
useEffect(() => {
if (checkedRef.current) {
checkedRef.current.focus();
} else if (firstRef.current) {
firstRef.current.focus();
}
}, []);
return (
<div className="App">
{
options.map((option, i) => {
const { id, label, value } = option;
const checked = invTheme === value;
return (
<div key={i}>
<Options
id={id}
label={label}
value={value}
checked={checked}
onChange={() => {
setInvTheme(value);
}}
/>
<br/><br/>
</div>
)
})
}
</div>
);
}
Options.tsx
import React, { useEffect } from 'react'
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
flexGrow: 1,
},
div: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border: '1px solid Gray'
},
selectedDiv: {
padding: theme.spacing(2),
margin: 'auto',
maxWidth: 700,
border: '2px solid Blue'
}
}),
);
export default function Options(props: any) {
const classes = useStyles();
const handleOnClick = (e: any) => {
if (e.type === "click" && e.clientX !== 0 && e.clientY !== 0) {
onChange({ target: value });
}
};
const { id, label, value, onChange, checked } = props;
return (
<div>
<div className={checked ? classes.selectedDiv : classes.div} onClick={handleOnClick}>
<Grid container spacing={2}>
<Grid item>
<input id={id} type="radio" name="type" aria-label={label} checked={checked} value={value} onChange={onChange}/>
</Grid>
<Grid item>
{label}
</Grid>
</Grid>
</div>
</div>
);
}