Currently I am working on a project where i am using react and redux to build it.
Scenario
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]
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.
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
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.
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.
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
i tried with getDerivedStateFromProps, but as i need to use SetState and its asynchronous, its not reflecting the current value.
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]
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);
- 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]);