如何将React-mentions组件与Material-UI(MUI) TextField结合使用?
问题描述
我正在开发应用的评论区,已经基于Material-UI(MUI)的TextField完成了样式和功能开发,效果符合预期。现在想集成react-mentions组件,希望找到不用替换现有TextField的可行方案。
我尝试过两种方式:
- 自定义组件方案:写了一个结合两者的组件,但TypeScript下遇到类型/接口错误,代码示例如下:
import React from 'react'; import { MentionsInput, Mention } from 'react-mentions'; import TextField, { TextFieldProps } from '@material-ui/core/TextField'; interface MentionTextFieldProps extends TextFieldProps { mentionsProps: { value: string; onChange: (value: string) => void; }; } const MentionTextField: React.FC<MentionTextFieldProps> = ({ mentionsProps, ...textFieldProps }) => { const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => { const { value } = event.target; mentionsProps.onChange(value); }; return ( <TextField {...textFieldProps} onChange={handleChange} multiline inputProps={{ style: { lineHeight: '1.5', whiteSpace: 'pre-wrap' }, }} > <MentionsInput value={mentionsProps.value} onChange={mentionsProps.onChange}> <Mention trigger="@" data={[]} /> </MentionsInput> </TextField> ); }; export default MentionTextField;
- 直接嵌套方案:把MentionsInput放在TextField的子元素里,代码不报错但react-mentions完全不生效,示例如下:
<TextField id="comment-field" onChange={handleChange} onKeyUp={handleKeyUp} name="comment" label="Leave a comment" multiline fullWidth minRows={2} placeholder="..." helperText={validationError ? errors[validationError] : ""} error={!!validationError} disabled={conditionsThatMakeTheTextFieldDisabled} sx={(theme) => ({ backgroundColor: context === "someSortOfContext" ? theme.palette.highlight.main : theme.palette.background.paper, })} color={context === "internal" ? "warning" : "primary"} > <MentionsInput value={commentValue} singleLine={false} onChange={(e) => setCommentValue(e.target.value)} > <Mention trigger="@" data={realUsers} /> </MentionsInput> </TextField>
单独使用react-mentions是正常工作的,但我不想替换现有的TextField组件。
可行的集成方案
核心思路是利用MUI TextField的inputComponent属性,将默认的输入组件替换为MentionsInput,同时保留TextField的所有样式和功能,这是官方支持的合规集成方式,能避免嵌套导致的DOM层级冲突。
1. 类型定义(解决TS类型问题)
先扩展TextField的Props,合并react-mentions所需的配置,确保类型安全:
import React from 'react'; import { MentionsInput, Mention, MentionsInputProps } from 'react-mentions'; import TextField, { TextFieldProps } from '@mui/material/TextField'; // 合并TextField属性与MentionsInput的核心配置 type MuiMentionsTextFieldProps = TextFieldProps & { mentions: Array<React.ReactElement<typeof Mention>>; mentionsInputProps?: Omit<MentionsInputProps, 'value' | 'onChange' | 'children'>; };
2. 实现自定义组件
创建组件,通过inputComponent把MentionsInput注入到TextField中,同时适配回调格式以兼容原有逻辑:
const MuiMentionsTextField: React.FC<MuiMentionsTextFieldProps> = ({ mentions, mentionsInputProps, value, onChange, multiline = true, ...textFieldProps }) => { // 适配react-mentions的onChange回调,模拟TextField的ChangeEvent结构 const handleMentionsChange = (newValue: string) => { onChange?.({ target: { value: newValue, name: textFieldProps.name }, } as React.ChangeEvent<HTMLTextAreaElement>); }; // 封装MentionsInput作为自定义输入组件 const CustomInput = React.forwardRef<HTMLDivElement, MentionsInputProps>((props, ref) => ( <MentionsInput ref={ref} value={value as string} onChange={handleMentionsChange} singleLine={!multiline} {...mentionsInputProps} > {mentions} </MentionsInput> )); return ( <TextField {...textFieldProps} value={value} onChange={undefined} // 禁用TextField自身的onChange,改用Mentions的回调 multiline={multiline} inputComponent={CustomInput} inputProps={{ ...textFieldProps.inputProps, style: { lineHeight: '1.5', whiteSpace: 'pre-wrap' }, }} /> ); };
3. 使用方式
直接像普通TextField一样使用,同时传入mentions配置,完全复用原有TextField的所有属性:
<MuiMentionsTextField id="comment-field" name="comment" label="Leave a comment" fullWidth minRows={2} placeholder="..." helperText={validationError ? errors[validationError] : ""} error={!!validationError} disabled={conditionsThatMakeTheTextFieldDisabled} sx={(theme) => ({ backgroundColor: context === "someSortOfContext" ? theme.palette.highlight.main : theme.palette.background.paper, })} color={context === "internal" ? "warning" : "primary"} value={commentValue} onChange={(e) => setCommentValue(e.target.value)} mentions={[ <Mention key="user" trigger="@" data={realUsers} />, // 可添加更多mention类型,比如#话题 // <Mention key="topic" trigger="#" data={topics} /> ]} mentionsInputProps={{ // 可选:配置react-mentions的额外属性,比如弹窗位置 popupPosition: "bottom", }} />
内容的提问来源于stack exchange,提问作者Nsp
相关产品推荐
相关产品推荐

