搜索查询以过滤React中的结果

时间:2019-10-13 03:00:05

标签: javascript node.js reactjs

我正在尝试基于简单的用户搜索输入来过滤数据。

我不确定是否是我过滤数据的方式,但是每当我在文本框中输入内容时,数据就会消失。我可以在开发工具中看到正在存储查询的状态。

这是我的上下文文件中的代码。我计划在搜索功能修复后再添加其他过滤器,这就是代码更复杂的原因。

    import * as React from "react";

const DefaultState = {
  cardListings: [],
  filter: {}
};

const CardListingsContext = React.createContext(DefaultState);

export const CardListingsConsumer = CardListingsContext.Consumer;

export class CardListingsProvider extends React.Component {
  static applyFilter(cards, filter) {
    const { query } = filter;
    let result = cards;
    if (query) {
      const search = query.toLowerCase();
      result = result.filter(item => item.title.indexOf(search) !== -1);
    }
    return result;
  }

  state = DefaultState;

  componentDidMount() {
    fetch("http://localhost:9000/mwBase")
      .then(res => res.json())
      .then(res => {
        this.setState({ cardListings: res });
      });
  }

  updateFilter = filter => {
    this.setState({
      filter
    });
  };

  render() {
    const { children } = this.props;
    const { cardListings, filter } = this.state;

    const filteredListings = CardListingsProvider.applyFilter(
      cardListings,
      filter
    );

    return (
      <CardListingsContext.Provider
        value={{
          allListings: cardListings,
          cardListings: filteredListings,
          updateFilter: this.updateFilter
        }}
      >
        {children}
      </CardListingsContext.Provider>
    );
  }
}

这是我的输入表格

<form
      className={formClasses}
      noValidate
      onChange={() =>
        setTimeout(() => this.props.updateFilter(this.state), 0)
      }
    >
      <p className="mb-1">Refine your results</p>
      <div className="form-group">
        <input
          type="text"
          className="form-control form-control-lg"
          placeholder="Search for a card..."
          name="query"
          value={this.state.query}
          onChange={event => this.setState({ query: event.target.value })}
        />
      </div>

以及在我的主页上应用过滤器的位置:

<CardListingsProvider>
          <CardListingsConsumer>
            {function(value) {
              const { cardListings, updateFilter } = value;
              return (
                <>
                  <Filter updateFilter={updateFilter} />
                  <div className="columns">
                    {cardListings.map(item => (
                      <Card key={item.itemId} card={item} />
                    ))}
                  </div>
                </>
              );
            }}
          </CardListingsConsumer>
        </CardListingsProvider>
              </div>

这是我的数据集的示例:

   [
{
itemId: [
"120901386991"
],
title: [
"1952 Topps Mickey Mantle Chase Card Box 18 packs 5 1950s or 1960's cards per box"
],
globalId: [
"EBAY-US"
],
subtitle: [
"3 BX LOT. 1 VINTAGE PK PER 25 BOXES* LOOK 4 1952 MANTLE"
],
primaryCategory: [
{
categoryId: [
"213"
],
categoryName: [
"Baseball Cards"
]
}
],
secondaryCategory: [
{
categoryId: [
"156521"
],
categoryName: [
"Vintage Non-Sport Cards"
]
}
],
galleryURL: [
"https://thumbs4.ebaystatic.com/m/m1mtMB65mAApWQ2EhJy4qWA/140.jpg"
],
viewItemURL: [
"https://rover.ebay.com/rover/1/711-53200-19255-0/1?ff3=2&toolid=10044&campid=5338164673&customid=watchbask&lgeo=1&vectorid=229466&item=120901386991"
],
paymentMethod: [
"PayPal"
],
autoPay: [
"true"
],
location: [
"USA"
],
country: [
"US"
],
shippingInfo: [
{
shippingServiceCost: [
{
@currencyId: "USD",
__value__: "0.0"
}
],
shippingType: [
"Free"
],
shipToLocations: [
"Worldwide"
],
expeditedShipping: [
"false"
],
oneDayShippingAvailable: [
"false"
],
handlingTime: [
"1"
]
}
],
sellingStatus: [
{
currentPrice: [
{
@currencyId: "USD",
__value__: "118.0"
}
],
convertedCurrentPrice: [
{
@currencyId: "USD",
__value__: "118.0"
}
],
sellingState: [
"Active"
],
timeLeft: [
"P10DT14H59M31S"
]
}
],
listingInfo: [
{
bestOfferEnabled: [
"false"
],
buyItNowAvailable: [
"false"
],
startTime: [
"2012-04-23T16:52:17.000Z"
],
endTime: [
"2019-10-23T16:52:17.000Z"
],
listingType: [
"FixedPrice"
],
gift: [
"false"
],
watchCount: [
"443"
]
}
],
returnsAccepted: [
"false"
],
condition: [
{
conditionId: [
"1000"
],
conditionDisplayName: [
"Brand New"
]
}
],
isMultiVariationListing: [
"false"
],
pictureURLLarge: [
"https://i.ebayimg.com/00/s/NTAwWDMxNA==/z/sT8AAOSw62VZv9qQ/$_1.JPG"
],
topRatedListing: [
"false"
]
},

1 个答案:

答案 0 :(得分:1)

在您的情况下,标题是字符串数组。如果应该仅包含一个元素。您可以从

更改过滤器功能
result.filter(item => item.title.indexOf(search) !== -1);

result.filter(item => item.title[0].indexOf(search) !== -1);

如果标题数组包含多个项目,则可以使用Array.some

result.filter(item =>
  item.title.some(eachTitle => {
    return eachTitle.indexOf(search) !== -1
  })
)

如果您需要不区分大小写的过滤器,则可能还需要更改该方面的过滤器功能。

const search = query.toLowerCase();
result.filter(item => item.title[0].toLowerCase().indexOf(search) !== -1);

您发布的代码段可能不完整。我在提供程序组件中看到了applyFilter函数的一些不平衡括号。

  static applyFilter(cards, filter) {
    const { query } = filter;
    let result = cards;
    if (query) {
      const search = query.toLowerCase();
      result = result.filter(item => item.title.indexOf(search) !== -1);
    }

  state = DefaultState;

我也想知道为什么您需要一个setTimeout来调用setState组件中的Filter函数。下面

onChange={() =>
          setTimeout(() => this.props.updateFilter(this.state), 0)
        }

您也可以摆脱它。

我进行了一些编辑以完成applyFilter函数,以返回过滤后的数据。请查看下面的代码和Run Code Snippet以查看实际代码。希望这会有所帮助!

// Provider Class

const DefaultState = {
  cardListings: [],
  filter: {}
};

const CardListingsContext = React.createContext(DefaultState);

const CardListingsConsumer = CardListingsContext.Consumer;

class CardListingsProvider extends React.Component {
  static applyFilter(cards, filter) {
    const {
      query
    } = filter;
    let result = cards;
    if (query) {
      const search = query.toLowerCase();
      result = result.filter(item => item.title[0].toLowerCase().indexOf(search) !== -1);
    }
    return result;
  }

  state = DefaultState;

  componentDidMount() {
    Promise.resolve([
  {
    itemId: ['1'],
    title: ['Apple']
  },
  {
    itemId: ['2'],
    title: ['Orange']
  },
  {
    itemId: ['3'],
    title: ['Peach']
  }
]).then(res => {
      this.setState({
        cardListings: res
      });
    });
  }

  updateFilter = filter => {
    this.setState({
      filter
    });
  };

  render() {
    const {
      children
    } = this.props;
    const {
      cardListings,
      filter
    } = this.state;

    const filteredListings = CardListingsProvider.applyFilter(
      cardListings,
      filter
    );

    return ( <
      CardListingsContext.Provider value = {
        {
          allListings: cardListings,
          cardListings: filteredListings,
          updateFilter: this.updateFilter
        }
      } >
      {
        children
      } 
      </CardListingsContext.Provider>
    );
  }
}



class Filter extends React.Component {
  state = { query: "" };
  render() {
    return (
      <form
        noValidate
        onChange={() =>
          setTimeout(() => this.props.updateFilter(this.state), 0)
        }
      >
        <p className="mb-1">Refine your results</p>
        <div className="form-group">
          <input
            type="text"
            className="form-control form-control-lg"
            placeholder="Search for a card..."
            name="query"
            value={this.state.query}
            onChange={event => this.setState({ query: event.target.value })}
          />
        </div>
      </form>
    );
  }
}




class Home extends React.Component {
  render() {
    return (
      <div>
        <CardListingsProvider>
          <CardListingsConsumer>
            {function(value) {
              const { cardListings, updateFilter } = value;
              return (
                  <React.Fragment>
                  <Filter updateFilter={updateFilter} />
                  <div className="columns">
                    {cardListings.map(item => (
                      <div key={item.itemId}>{JSON.stringify(item)}</div>
                    ))}
                  </div>
                  </React.Fragment>
              );
            }}
          </CardListingsConsumer>
        </CardListingsProvider>
      </div>
    );
  }
}





ReactDOM.render( <Home /> , document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id="root"></div>