0

Currently I am working on a project where i am using react and redux to build it.

Scenario

  1. There is a toggle button which will toggle between Group Queue and My Queue. Both these will hit a api and load the data(list of tickets) .[i.e. 2 separate entities]

  2. Now there is a search box while will give the result based on the value i enter. I have added the 'Delay functionality' i.e. after 2 seconds onChange event will fire and it will dispatch an action to all reducers.

image

Problem

Let's say, i search for a value(68) under group Queue, it works fine. Now if i toggle to my queue, SearchBox value should be null.but it shows as 68 As i told, both queue are separate bodies, if i toggle, searchBox's value should disappear, but its not.

Reason

  1. i am storing a state of search box value and timer to set the value on typing after 2 seconds and on every character I type, setTimeOut and clearTimeOut will be invoked to accommodate the delay functionality.

  2. Thus i have a state inside my React SearchBox Component and once i type and stay put for 2 seconds, then it will dispatch the action via useEffect/ComponentDidUpdate.

  3. i decided to have a state inside the component as i did not want to fire an action on every character user types. Only the intended search Value Redux should store.

Things i tried

  1. i tried with getDerivedStateFromProps, but as i need to use SetState and its asynchronous, its not reflecting the current value.

  2. i have added 2 functionality (onChange and OnEnter). With OnEnter, i think it will work as i can pass the redux store's value and action to the input's value and OnEnter attribute. [i have not tried]

  3. But i want to have the delay functionality. Can anyone suggest an alternative ?

Codes

1. SearchComponent

import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { filterAction } from "../../actions";
import "./search.css";

const WAIT_INTERVAL = 2000;
const ENTER_KEY = 13;

const Search = (props) => {
  console.log("search", props.value);
  let [value, setValue] = useState(props.value);
  let [timer, setTimer] = useState(0);

  useEffect(() => {
    setTimer(
      setTimeout(() => {
        if (timer) props.filterAction("SEARCH_FILTER", value);
      }, WAIT_INTERVAL)
    );
    return () => clearTimeout(timer);
  }, [value]);

  const handleKeyDown = (event) => {
    if (event.keyCode === ENTER_KEY) {
      clearTimeout(timer);
      props.searchAction("SEARCH_FILTER", value);
    }
  };

  //  GETDERIVEDSTATEFROMPROPS
  // if (props.value !== value) {
  //   setValue("");
  //   // console.log("check2", props.value, value);
  // }

  return (
    <input
      className="search-box"
      type="search"
      placeholder="Search any Request Id/ Email Id..."
      aria-label="Search"
      value={value}
      onChange={(e) => setValue(e.target.value)}
      onKeyDown={handleKeyDown}
    ></input>
  );
};

const mapStateToProps = (store) => ({
  value: store.filterValues.searchFilter,
});

export default connect(mapStateToProps, { filterAction })(Search);
  1. Redux Redcuer (FilterReducer) -- working fine i.e. on toggling, searchValue is getting emptied('').
export const filterReducer = (filterValues = {}, action) => {
      switch (action.type) {
        case "TOGGLE_QUEUE":
          return {
            order: [],
            tileFilter: action.payload.tileType,
            searchFilter: "",
            buttonFilter: {},
            timelineFilter: "all",
          };
       case "SEARCH_FILTER":
           let arr = [...filterValues.order];
           arr.push("SEARCH_FILTER");
           let ob = {
              ...filterValues,
              searchFilter: action.payload.value,
              order: arr,
           };
          return ob;
         }
      return filterValues;
    };

Please let me know if you have any solutions.

EDIT 1 i tried with props.value on UseEffect, now the search itself is not working..

useEffect(() => {
    // setValue(props.value); // not working

    setTimer(
      setTimeout(() => {
        if (timer) props.filterAction("SEARCH_FILTER", value);
      }, WAIT_INTERVAL)
    );
    setValue(props.value); // not working

    return () => clearTimeout(timer);
  }, [props.value]);

Edit2

i added a separate useffect as suggested by Sabbit, but if i type 68, the search functionality is getting invoked on 6 and typed value (68) alternatively.

   useEffect(() => {
    setTimer(
      setTimeout(() => {
        if (timer && value.length > 0)
          props.filterAction("SEARCH_FILTER", value);
      }, WAIT_INTERVAL)
    );
    return () => clearTimeout(timer);
  }, [value]);

  useEffect(() => {
    if (value !== props.value) setValue(props.value);
  }, [props.value]);

teddcp
  • 1,514
  • 2
  • 11
  • 25

1 Answers1

0

Did you tried using another useEffect for props.value?

useEffect(() => {
  setTimer(
    setTimeout(() => {
       if (timer && value.length > 0) props.filterAction("SEARCH_FILTER", value);
    }, WAIT_INTERVAL)
  );
  return () => clearTimeout(timer);
}, [value]);

useEffect(() => {
   setValue(props.value);
}, [props.value]);

That will update the value in the state each time the props.value is changed. I believe the searchValue from reducer is passed via props to the Search component.

Update: I have updated the condition to execute props.filterAction("SEARCH_FILTER", value) from if(timer) to if(timer && value.length > 0). We need to do that because everytime the props changes we are setting the value in state and we have used an useEffect depending on the change of value in state. That is why it is searching with empty string. We need to make sure that the searching doesn't happen unless we have something in the input field.

Md Sabbir Alam
  • 4,937
  • 3
  • 15
  • 30
  • i tried that , now the search is not happening.. Please see the edit1 section – teddcp Oct 31 '20 at 13:01
  • you can create multiple useEffect. You are not supposed to update the previous useEffect just add another useEffect under that. – Md Sabbir Alam Oct 31 '20 at 13:05
  • I have update my code. Please look at that. Your previous useEffect should be as it was. Just add another useEffect method call after that. – Md Sabbir Alam Oct 31 '20 at 13:07
  • You are not declaring any timer in the 2nd useEffect so you should not clear anything there. – Md Sabbir Alam Oct 31 '20 at 13:08
  • hi, nope.. though its clearing the value on every toggle, but the searching is happening on every second.. like its automatically invoking an empty value and typed value on each second – teddcp Oct 31 '20 at 13:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223910/discussion-between-sabbir-alam-and-tedd). – Md Sabbir Alam Oct 31 '20 at 13:13
  • I have updated the first useEffect code a bit. Please check now. I will add an explanation in my answer now. – Md Sabbir Alam Oct 31 '20 at 13:15