title: React Apollo GraphQL Search/Filter
body: <p>I have a React project with a GraphQL server using Apollo client. I am trying to figure out how to change the query result based on search text and filtering selections. If someone could look at my code and give me some help, I would greatly appreciate it. Sorry about all the code, I thought maybe it all might be relevant.</p>
  
  <p><strong>server/index.js</strong></p>
  
  <pre><code>const resolvers = {
    Query: {
      getClasses: () =&gt; classes,
      searchClasses: () =&gt; classes
    },
  };
  
  const server = new ApolloServer({ typeDefs, resolvers });
  
  const app = express();
  app.use(cors());
  app.use(bodyParser.text({ type: 'application/graphql' }));
  server.applyMiddleware({ app });
  
  app.listen({ port: 4000 }, () =&gt;
    console.log(` Server ready at http://localhost:4000${server.graphqlPath}`)
  );
  </code></pre>
  
  <p><strong>server/schema.js</strong></p>
  
  <pre><code>const typeDefs = `
    type Class {
      entry_id: ID!
      title: String
      url: String
      thumb: String
      duration: [String]
      style: [String]
      intensity: [String]
      anatomical_focus: [String]
      level: [String]
      teacher: [String]
      authorId: Int
      live_start: Int
      live_end: Int
      type: String
      logged_in_member_id: Int
      favorite: Boolean
      favorite_order: Int
      favorited_on: Int
      body_snippet: String
    }
  
    input Filters {
      teacher: String
      duration: String
      level: String
      style: String
      anatomy: String
    }
  
    type Query {
      getClasses: [Class]!
      searchClasses(search: String, filters: Filters): [Class]!
    }
  `;
  
  module.exports = typeDefs;
  </code></pre>
  
  <p><strong>client/src/index.js</strong></p>
  
  <pre><code>const client = new ApolloClient({
    uri: 'http://localhost:4000/graphql',
    cache: new InMemoryCache()
  });
  
  ReactDOM.render(
    &lt;ApolloProvider client={client}&gt;
      &lt;Header /&gt;
      &lt;Router&gt;
        &lt;Route exact path='/' component={App}/&gt;
      &lt;/Router&gt;
    &lt;/ApolloProvider&gt;, 
    document.getElementById('root')
  );
  serviceWorker.unregister();
  </code></pre>
  
  <p><strong>queries/search</strong></p>
  
  <pre><code>const SEARCH_CLASSES = gql`
    query SearchClasses($search: String, $filters: Filters) {
      searchClasses(search: $search, filters: $filters) {
        entry_id
        title
        url
        thumb
        duration
        style
        intensity
        level
        teacher
        body_snippet
      }
    }
  `;
  </code></pre>
  
  <p><strong>client/src/pages/Classes.js</strong></p>
  
  <pre><code>class Classes extends Component {
      constructor(props) {
          super(props);
          this.state = { keyword: '', filters: { teacher: '', duration: '', level: '', style: '', anatomy: '' } };
          this.setSearch = this.setSearch.bind(this);
          this.setFilters = this.setFilters.bind(this);
      }
      setSearch(e) {
          this.setState({
              keyword: e.target.value
          });
      }
      setFilters(e) {
          this.setState({
              filters: e.target.value
          })
      }
      componentDidMount() {
          var ddToggle = document.querySelectorAll('.dropdown-toggle');
          ddToggle.forEach(function (dd) {
              dd.addEventListener("click", function(ev) {
                  dd.nextSibling.classList.toggle('show');
              });
          });
      }
  
      render() {
          let text = this.state.keyword;
          let teacher = this.state.filters.teacher;
          let duration = this.state.filters.duration;
          let level = this.state.filters.level;
          let style = this.state.filters.style;
          let anatomy = this.state.filters.anatomy;
          return (
              &lt;Query
                  query={Queries.Search}
                  variables={{
                      search: text,
                      filters: {
                          teacher: '',
                          duration: '',
                          level: '',
                          style: '',
                          anatomy: ''
                      }
                  }}&gt;
                  {({ loading, error, data }) =&gt; {
                      if (loading) return &lt;p&gt;Loading...&lt;/p&gt;;
                      if (error) return &lt;p&gt;Error: ${error}&lt;/p&gt;;
                      return (
                          &lt;div&gt;
                              &lt;section className="ygi-search"&gt;
                              &lt;div className="container px-3"&gt;
                                  &lt;div className="ygi-search__wrapper"&gt;
                                      &lt;SearchBar handleSearch={this.setSearch} search={ text } /&gt;
                                      &lt;button className="ygi-search__filter-btn mx-auto mb-2 " aria-label="Shows Filters"&gt;Show Filters&lt;/button&gt;
                                      &lt;div className="yi-dropdowns__wrapper-visibility col-lg-10 "&gt;
                                          &lt;div className="row"&gt;
                                              &lt;TeachersDD handleSelect={this.setFilters} selection={ teacher } /&gt;
                                              &lt;DurationDD  handleSelect={this.setFilters} selection={ duration } /&gt;
                                              &lt;LevelDD handleSelect={this.setFilters} selection={ level } /&gt;
                                              &lt;StyleDD handleSelect={this.setFilters} selection={ style } /&gt;
                                              &lt;AnatomyDD handleSelect={this.setFilters} selection={ anatomy } /&gt;
                                          &lt;/div&gt;
                                      &lt;/div&gt;
                                  &lt;/div&gt;
                              &lt;/div&gt;
                          &lt;/section&gt;
                              &lt;div className="flex"&gt;
                                  {data.searchClasses.map(single =&gt; (
                                      &lt;Class class={single} key={single.entry_id} /&gt;
                                  ))}
                              &lt;/div&gt;
                          &lt;/div&gt;
                      )
                  }}
              &lt;/Query&gt;
          );
      }
  }
  
  export default Classes;
  </code></pre>
  
  <p><strong>client/src/components/Search.js</strong></p>
  
  <pre><code>class SearchBar extends Component {
  
      render() {
          return (
              &lt;div className="ygi-search-bar col col-12 col-lg-2"&gt;
                  &lt;div className="ygi-search-bar__wrapper mt-2"&gt;
                      &lt;input onChange={this.props.handleSearch} placeholder="Search" value={this.props.search} type="text" className="ygi-search-bar__input" /&gt;
                      &lt;a href="true" className="icon-wrapper ygi-search-bar__icon-wrapper" style={{ bottom: "calc(50%)" }}&gt;
                          &lt;svg role="presentation" className="icon-search-grey"&gt;
                              &lt;use xlinkHref="#icon-search-grey"&gt;&lt;/use&gt;
                          &lt;/svg&gt;
                      &lt;/a&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          );
      }
  }
  
  SearchBar.propTypes = {
      handleSearch: PropTypes.func,
      text: PropTypes.string
  };
  
  export default SearchBar;
  </code></pre>