我想在用户在输入字段中输入@时显示所有可用的用户名,而在用户在@字符后输入任何内容时过滤用户名。
我已经像下面那样实现了
class UserMention extends React.purecomponent {
constructor(props) {
super(props);
this.state = {
text: '',
user_mention: false,
};
this.user='';
}
user_list = [
{name: 'John smith'},
{name: 'Jenna surname2'},
{name: 'Tuija rajala'},
];
get_user = s => s.includes('@') && s.substr(s.lastIndexOf('@') +
1).split(' ')[0];
handle_input_change = (event) => {
let user_mention;
this.user = this.get_user(event.target.value);
if (event.target.value.endsWith('@')) {
user_mention = true;
} else {
user_mention = false;
}
this.setState({
user_mention: user_mention,
[event.target.name]: event.target.value,
});
};
get_text_with_user_mention = (text, selected_user) => {
let user_name = selected_user;
let text_without_user_mention;
text_without_user_mention = text.slice(0,
text.lastIndexOf('@'));
return text_without_user_mention + user_name;
};
handle_select_value = (selected_user) => {
let text;
text = this.get_text_with_user_mention(this.state.text,
selected_user);
this.setState({
text: text,
user_mention: false,
});
this.user = false;
};
render = () => {
let suggested_values = [];
if (this.state.user_mention) {
suggested_values = this.user_list
.map((o) => { return {user_name: o.user_name};});
}
if (this.user) {
suggested_values = this.user_list
.filter(user => user.user_name.indexOf(this.user) !==
-1)
.map((o) => {return {user_name: o.user_name};});
}
return (
<input
required
name="text"
value={this.state.text}
onChange={this.handle_input_change}
type="text"/>
{this.state.user_mention &&
<SelectInput
on_change={this.handle_select_value}
values={suggested_values}/>}
{this.user &&
<SelectInput
on_change={this.handle_select_value}
values={suggested_values}/>}
);
};
}
如您从上面的代码中看到的,我正在基于this.user和this.state.user_mention状态修改建议值。有人可以帮我重构或修改它更好一点。谢谢。
答案 0 :(得分:1)
这是使用React钩子而不是类的另一种方法。如果您从未使用过挂钩,请尝试一下。您会喜欢的。我认为这要简单得多。
我还添加了一个username
属性。如果您在标记某人时使用不允许空格的字符串,那就更好了。如果需要,还可以显示全名,并带有空格和username
。
例如:
John Smith (@johnsmith)
function App() {
const inputRef = React.useRef(null);
const [inputValue, setInputValue] = React.useState('');
const [userList,setUserList] = React.useState([
{name: 'John smith', username:'johnsmith'},
{name: 'Jenna surname2', username:'jennasurname2'},
{name: 'Tuija rajala', username:'tuijarajala'}
]
);
const [showSuggestions,setShowSuggestions] = React.useState(false);
const [suggestionList,setSuggestionList] = React.useState(
['johnsmith','jennasurname2','tuijarajala']
);
function onChange(event) {
const regexp = /@[a-zA-Z0-9]*$/;
if (regexp.test(event.target.value)) {
setShowSuggestions(true);
}
else {
setShowSuggestions(false);
}
setInputValue(event.target.value);
}
function focusInput() {
inputRef.current.focus();
}
return(
<React.Fragment>
<input ref={inputRef} type='text' value={inputValue} onChange={onChange}/>
{showSuggestions &&
<Suggestions
inputValue={inputValue}
suggestionList={suggestionList}
applyMention={onChange}
focusInput={focusInput}
/>
}
</React.Fragment>
);
}
function Suggestions(props) {
function selectSuggestion(username) {
const regexp = /@[a-zA-Z0-9]*$/;
const newValue = props.inputValue.replace(regexp,username + ' ');
props.applyMention({target: {value: newValue}}); // THIS MIMICS AN ONCHANGE EVENT
props.focusInput();
}
const suggestionItems = props.suggestionList.map((item) =>
<div className="item" onClick={()=>selectSuggestion('@' + item)}>@{item}</div>
);
return(
<div className="container">
{suggestionItems}
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
.container {
border: 1px solid silver;
width: 150px;
}
.item {
cursor: pointer;
}
.item:hover {
color: blue;
}
input {
width: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
答案 1 :(得分:0)
您可以通过执行以下操作来简化代码。
请参阅沙箱:https://codesandbox.io/s/react-example-kgm2h
从“ react-dom”导入ReactDOM; 从“反应”导入React;
class UserMention extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
user_list: [
{ name: "John smith" },
{ name: "Jenna surname2" },
{ name: "Tuija rajala" }
],
suggestions: []
};
}
handleOnChange = e => {
const { value } = e.target;
const { user_list } = this.state;
//show all user suggestions
if (value.includes("@") && value.indexOf("@") === value.length - 1) {
this.setState({
text: value,
suggestions: [...this.state.user_list]
});
//show matching user suggesstions
} else if (value.includes("@") && value.length > 1) {
const stringAfterAt = value.slice(value.indexOf("@") + 1).toLowerCase();
const newSuggestions = user_list.filter(user => {
return user.name.toLowerCase().includes(stringAfterAt);
});
this.setState({
text: value,
suggestions: newSuggestions
});
//display no users if they do not use the @ symbol
} else {
this.setState({
text: value,
suggestions: []
});
}
};
createSuggestionsList = () => {
const { suggestions } = this.state;
return suggestions.map(user => {
return <div>{user.name}</div>;
});
};
render = () => {
return (
<div>
<input
required
name="text"
value={this.state.text}
onChange={this.handleOnChange}
type="text"
/>
{this.createSuggestionsList()}
{/* <SelectInput value={this.state.suggestions}/> */}
</div>
);
};
}
ReactDOM.render(<UserMention />, document.getElementById("root"));
我不确定您要如何呈现建议的用户,但是您始终可以将this.state.suggestions
传递给SelectInput
组件。
主要收获是在array
中使用state
中的附加suggestions
,并在用户键入input
时对其进行更新。我们在{this.createSuggestionsList()}
内部调用render
,为每个建议的用户动态创建标记。或如上所述,只需将suggestions
传递为prop
。