React 使用 Typescript 创建动态引用
React creating dynamically refs with Typescript
我有一个 table
列表,其中每一行都有一个 menu
按钮,为此我需要一个 ref
。我在我的项目中使用了 react mui,它是 menu。我试过像这样创建参考:
const {rows} = props;
const refs = Array.from({length: rows.length}, a => React.useRef<HTMLButtonElement>(null));
然后尝试在每个 button
:
上使用像这样的 map
函数
<Button
ref={refs[index]}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs[index].current)}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs[index].current)}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs[index].current)}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs[index].current)}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
但是,然后我得到一个错误:
React Hook "React.useRef" cannot be called inside a callback. React
Hooks must be called in a React function component or a custom React
Hook function react-hooks/rules-of-hooks
如何动态执行此操作,以便我可以在 map 函数中使用 refs。我已经尝试过答案中的建议,但我无法让它发挥作用。
这是 codesandbox of the example.
useRef
与 React.createRef 并不完全相同。
最好叫它 useInstanceField
:)
因此,您的代码可能有点不同。
第一步:我们使用useRef
保存refs数组:
const {rows} = props;
const refs = useRef(Array.from({length: rows.length}, a => React.createRef()));
然后,在您的 map 函数中,我们将每个 ref 保存到其在 refs 数组中的索引:
<Button
ref={refs.current[index]}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs.current[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs.current[index].current)}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs.current[index].current)}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index].current)}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index].current)}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
如果你的长度改变了,你应该在useEffect
中处理它来改变refs的长度
您也可以使用另一种方式:
1) 创建一个引用数组,但没有 React.createRef:
const {rows} = props;
const refs = useRef(new Array(rows.length));
在 map 中我们使用 ref={el => refs.current[index] = el}
来存储 ref
<Button
ref={el => refs.current[index] = el}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs.current[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs.current[index])}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs.current[index])}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index])}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index])}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
这里还有一个选项:
const textInputRefs = useRef<(HTMLDivElement | null)[]>([])
...
const onClickFocus = (event: React.BaseSyntheticEvent, index: number) => {
textInputRefs.current[index]?.focus()
};
...
{items.map((item, index) => (
<textInput
inputRef={(ref) => textInputs.current[index] = ref}
/>
<Button
onClick={event => onClickFocus(event, index)}
/>
}
我有一个 table
列表,其中每一行都有一个 menu
按钮,为此我需要一个 ref
。我在我的项目中使用了 react mui,它是 menu。我试过像这样创建参考:
const {rows} = props;
const refs = Array.from({length: rows.length}, a => React.useRef<HTMLButtonElement>(null));
然后尝试在每个 button
:
map
函数
<Button
ref={refs[index]}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs[index].current)}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs[index].current)}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs[index].current)}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs[index].current)}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
但是,然后我得到一个错误:
React Hook "React.useRef" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
如何动态执行此操作,以便我可以在 map 函数中使用 refs。我已经尝试过答案中的建议,但我无法让它发挥作用。 这是 codesandbox of the example.
useRef
与 React.createRef 并不完全相同。
最好叫它 useInstanceField
:)
因此,您的代码可能有点不同。
第一步:我们使用useRef
保存refs数组:
const {rows} = props;
const refs = useRef(Array.from({length: rows.length}, a => React.createRef()));
然后,在您的 map 函数中,我们将每个 ref 保存到其在 refs 数组中的索引:
<Button
ref={refs.current[index]}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs.current[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs.current[index].current)}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs.current[index].current)}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index].current)}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index].current)}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
如果你的长度改变了,你应该在useEffect
中处理它来改变refs的长度
您也可以使用另一种方式:
1) 创建一个引用数组,但没有 React.createRef:
const {rows} = props;
const refs = useRef(new Array(rows.length));
在 map 中我们使用 ref={el => refs.current[index] = el}
来存储 ref
<Button
ref={el => refs.current[index] = el}
aria-controls="menu-list-grow"
aria-haspopup="true"
onClick={() => handleToggle(row.id)}
>Velg
</Button>
<Popper open={!!checkIfOpen(row.id)} anchorEl={refs.current[index].current} keepMounted transition disablePortal>
{({TransitionProps, placement}) => (
<Grow
{...TransitionProps}
style={{transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom'}}>
<Paper id="menu-list-grow">
<ClickAwayListener onClickAway={(e) => handleClose(e, refs.current[index])}>
<MenuList>
<MenuItem
onClick={(e) => handleClose(e, refs.current[index])}>Profile</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index])}>My account</MenuItem>
<MenuItem onClick={(e) => handleClose(e, refs.current[index])}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
这里还有一个选项:
const textInputRefs = useRef<(HTMLDivElement | null)[]>([])
...
const onClickFocus = (event: React.BaseSyntheticEvent, index: number) => {
textInputRefs.current[index]?.focus()
};
...
{items.map((item, index) => (
<textInput
inputRef={(ref) => textInputs.current[index] = ref}
/>
<Button
onClick={event => onClickFocus(event, index)}
/>
}