如何使用reactjs根据用户输入列出所有建议和已过滤建议?

时间:2019-07-03 06:33:57

标签: javascript reactjs

我想在用户在输入字段中输入@时显示所有可用的用户名,而在用户在@字符后输入任何内容时过滤用户名。

我已经像下面那样实现了

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状态修改建议值。有人可以帮我重构或修改它更好一点。谢谢。

2 个答案:

答案 0 :(得分:1)

这是使用React钩子而不是类的另一种方法。如果您从未使用过挂钩,请尝试一下。您会喜欢的。我认为这要简单得多。

enter image description here

我还添加了一个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