【问题标题】:How to use search input suggestions in React如何在 React 中使用搜索输入建议
【发布时间】:2019-05-20 12:39:22
【问题描述】:

我有一个从 API 调用返回的主题和组的列表。主题至少属于 1 个或多个组。当前按所选组过滤主题。在 selectedGroups 状态中设置或删除每个选定的组。我有一个输入搜索框,用于帮助用户在开始在文本框中输入时找到主题。我想要一个下拉菜单,显示是否有任何主题标题与他们的搜索输入匹配。

示例..如果我输入..

“乔” 主题状态应更新包含文本“Jo”的所有主题名称

过滤的主题: 约翰 约翰尼 琼等

我有名为 handleInputChange 的搜索输入和 onchange 方法 我收到一个错误:“PracticeAreas”类型上不存在属性“搜索”。 并且不知道我应该去哪里让它正常工作。 任何帮助将非常感激,谢谢

我已包含来自 API 调用的示例数据 还有反应脚本

主要:

import * as React from 'react';
import './PracticeAreas.css';
import IReportGroup from 'src/model/IReportGroup';
import { Loader } from '../loader/Loader';
import Suggestions from './Suggestions'

export interface IGroupTopics {
    id: string
    name: string,
    groups: string[]
}

interface IOwnProps {

}

interface IOwnState {
    groups: IReportGroup[],
    topics: IGroupTopics[],
    selectedGroups: IReportGroup[],
    query: string,
}

class PracticeAreas extends React.Component<IOwnProps, IOwnState> {

    constructor(props: IOwnProps) {
        super(props);

        this.state = {
          groups: [],
          topics: [],
          selectedGroups: [],
          query: ""
        }
      }

    public render() {
        const { topics } = this.state;

        return topics.length > 0 ?
            this.renderData(topics) :
            <Loader />
    }

    public renderData(data: any) {
        return (
        <div className="col-md-12 practiceAreas">
            <h1>Practice Areas</h1>

            <div className="selection-refinement">
                <div className="refinement-search">
                    <form>
                        <input
                        placeholder="Search for..."
                        ref={input => this.search = input}
                        onChange={this.handleInputChange}
                        />
                        <Suggestions topics={this.state.topics} />
                    </form>
                </div>
            </div>

            <ul className="list-inline groupedTags">
                {this.state.groups.map((item,i) => 
                    <li key={i}>
                        <a className={"navigator-tags " + (this.groupInState(item) ? "active" : "")} onClick={() => this.setSelectedGroups(item)}>
                            {item.name}
                        </a>
                    </li>
                )}
            </ul>

            <div className="row practiceAreasContainer">
                {this.state.topics.filter(topic => this.topicInGroupSelection(topic)).map((item,i) => 
                    <div key={i} className="result">
                        <div className="col-md-6 result-item">
                            <div className="item-container default shadowed item-content highlight row">
                                <div className="col-sm-12 no-padding">
                                    <p>Editor: <a href="#">John Sinclair</a>, <a href="#">Eric Draven</a>, <a href="#">Coco Zames</a></p>
                                    <p><a href="#">Beiten Burkhardt</a></p>
                                    <div className="row no-margin">
                                        <div className="col-12 col-sm-10 text-content">
                                            <h3>
                                                <a href="#" >{item.name}</a>
                                            </h3>
                                            <p className="summary">
                                                Summary
                                            </p>
                                        </div>
                                        <div className="col-10 col-sm-2 links-container rhs">
                                            <a href="#">Compare</a>
                                            <div className="divider" />
                                            <a href="#">View</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                )}
            </div>
            <div className="row text-center">
                <a className="lex-primary-btn medium-btn">Load more</a>
            </div>
        </div>
        );
    }

    public handleInputChange = () => {
        this.setState({
          query: this.search.value
        }, () => {
          if (this.state.query && this.state.query.length > 1) {
            // this.showDropdown()
            if (this.state.query.length % 2 === 0) {
              this.state.topics
            }
          } else if (!this.state.query) {
            // this.hideDropdown()
          }
        })
      }

    public componentDidMount() {
        fetch(`.../api/v2/navigator/reports/topics`, {
            method: "GET",
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json"
            }})
        .then((res) => res.json()
        .then((data) => { 
            this.setState({ 
                groups: data.groups,
                topics: data.data
            });
        }));
    }

    public setSelectedGroups = (group: IReportGroup) => { 
        // remove from state
        if (this.groupInState(group)) {
            this.setState(state => ({
                selectedGroups: state.selectedGroups.filter(t => t.id !== group.id)
            }));      
        // set state       
        } else {
            this.setState(previousState => ({
                selectedGroups: [...previousState.selectedGroups, group]
            }));        
        }
    }

    public topicInGroupSelection = (topic: IGroupTopics) => { 
        return (this.state.selectedGroups.length > 0 ? this.state.selectedGroups.some(item => topic.groups.some(group => group === item.id)) : true)
    } 

    public groupInState = (group: IReportGroup) => {
        return this.state.selectedGroups.some(item => group.id === item.id);
    }
}

export default PracticeAreas

建议(应该是状态中的主题):

import * as React from 'react';

const Suggestions = (props) => {
  const options = props.topics.map(r => (
    <li key={r.id}>
      {r.name}
    </li>
  ))
  return <ul>{options}</ul>
}

export default Suggestions

数据示例:

<ReportSelectionCriteriaResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
    <Data xmlns:d2p1="http://schemas.datacontract.org/2004/07/">
        <d2p1:NavigatorReportSelection>
            <d2p1:About>test title 4</d2p1:About>
            <d2p1:Groups xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
                <d4p1:guid>d21384b5-27be-4bfc-963d-0d2ad40dbbfb</d4p1:guid>
            </d2p1:Groups>
            <d2p1:Id>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d2p1:Id>
            <d2p1:Name>Test</d2p1:Name>
            <d2p1:ParentId i:nil="true"/>
            <d2p1:Selected>false</d2p1:Selected>
            <d2p1:Type>Topics</d2p1:Type>
            <d2p1:Visible>true</d2p1:Visible>
        </d2p1:NavigatorReportSelection>
        <d2p1:NavigatorReportSelection>
            <d2p1:About i:nil="true"/>
            <d2p1:Groups xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
                <d4p1:guid>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d4p1:guid>
            </d2p1:Groups>
            <d2p1:Id>47cb7f1d-2267-426c-9f7f-0df3b9291fb7</d2p1:Id>
            <d2p1:Name>Another test topic</d2p1:Name>
            <d2p1:ParentId i:nil="true"/>
            <d2p1:Selected>false</d2p1:Selected>
            <d2p1:Type>Topics</d2p1:Type>
            <d2p1:Visible>true</d2p1:Visible>
        </d2p1:NavigatorReportSelection>
    </Data> 
    <Groups xmlns:d2p1="http://schemas.datacontract.org/2004/07/">
        <d2p1:NavigatorReportSelectionGroup>
            <d2p1:Focused>false</d2p1:Focused>
            <d2p1:Id>2fb2783c-f48e-4d49-8098-0d39e4a16e7a</d2p1:Id>
            <d2p1:Name>Allan's Test group</d2p1:Name>
            <d2p1:Order>0</d2p1:Order>
            <d2p1:Type>Topics</d2p1:Type>
        </d2p1:NavigatorReportSelectionGroup>
        <d2p1:NavigatorReportSelectionGroup>
            <d2p1:Focused>false</d2p1:Focused>
            <d2p1:Id>47cb7f1d-2267-426c-9f7f-0df3b9291fb7</d2p1:Id>
            <d2p1:Name>Another test topic group</d2p1:Name>
            <d2p1:Order>1</d2p1:Order>
            <d2p1:Type>Topics</d2p1:Type>
        </d2p1:NavigatorReportSelectionGroup>
    </Groups>
</ReportSelectionCriteriaResponse>

【问题讨论】:

    标签: reactjs search filter state onchange


    【解决方案1】:
      handleInputChange = e => {
        let newState = Object.assign({}, this.state);
        newState.matchedResults = [];
        newState.topics.forEach(topic => {
          if (
            topic.name.toLowerCase().indexOf(e.target.value.toLowerCase()) !== -1 &&
            e.target.value.length > 0
          ) {
            newState.matchedResults.push(topic);
          }
        });
        this.setState(newState, () => {
          console.log("Your found results", this.state.matchedResults);
        });
      };
    

    在您的视图中呈现this.state.matchedResults 的地图

    【讨论】:

    • 谢谢,但我在这里收到一个错误,说属性搜索确实存在; ref={input => this.search = input} 你知道这里有什么问题吗? ——
    • 不知道。上面的函数适用于我拥有的 this.state.topics 数组和输入 onChange 就好了。
    • 我想是因为我错误地映射了 matchResults,你能展示一下你是如何映射它的吗?同样在编译时,当我将它放在状态/构造函数中并编译它时,我会在 Readonly 类型上得到 matchResults 并说它不能被分配,因为它是一个常量或只读的,.
    猜你喜欢
    • 2023-03-29
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 2020-11-09
    • 2021-07-27
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多