Reputation: 81
I'm new to react, I have a search bar, when I enter something, it automatically updates the results, but I want to be able to navigate away from the page and when I come back, I want it to be persisted. The search should be retained until manually cleared by the user.
This is my code so far:
import { useEffect, useRef, useState } from "react";
import { useOnClickOutside } from "../../hooks";
import useDebounce from "../../hooks/useDebounce";
import { ISearchProps } from "./search.props";
import { SearchWrapper } from "./Search.style";
const Search: React.FC<ISearchProps> = ({onChange, placeholder = "Search by..."}) => {
const [value, setValue] = useState<string>("");
const debouncedValue = useDebounce(value, 500);
const [expandInput, setExpandInput] = useState(false);
const ref = useRef(null);
const [input, setInput] = useState<HTMLInputElement | null>();
useEffect(()=>{
onChange(debouncedValue);
window.localStorage.setItem('SAVE_SEARCH', JSON.stringify(value));
}, [debouncedValue]);
useEffect(()=>{
const data = window.localStorage.getItem('SAVE_SEARCH');
if (data !== null)
setValue(JSON.parse(data))
}, [setValue]);
useEffect(()=>{
expandInput && input?.focus();
}, [expandInput]);
const searchHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
}
useOnClickOutside(ref, () => value === "" && setExpandInput(false));
return(
<SearchWrapper expandInput={expandInput} ref={ref}>
<input ref={inputEl => setInput(inputEl)} type="text" onChange={(e) => searchHandler(e)} value={value} placeholder={placeholder} />
{ (expandInput && (value.length > 0)) && <i className="ico-Exit" onClick={()=> setValue("")} ></i>}
<button className="search-button" onClick={() => setExpandInput(true)}>
<i className="ico-Search"></i>
</button>
</SearchWrapper>
)
}
export default Search;
I can see this in dev tools > Storage, it's updating as I type:
Not sure what I'm missing, please help!
Upvotes: 3
Views: 10078
Reputation: 1116
First, set localStorage with the same value which you are storing in to State.
const saveCartData = (cartData) => {
setCartItemsList(cartData);
localStorage.setItem("cartItems", JSON.stringify(cartData));
};
Second while initializing your state get the localStorage value
const cartInitialValue = () => {
return JSON.parse(localStorage.getItem("cartItems")) || [];
};
Apply local storage value to initial value of state.
const [cartItemsList, setCartItemsList] = useState(cartInitialValue);
Upvotes: 1
Reputation: 99
Write yourself a custom react hook:
import { useEffect, useState } from "react";
export default function usePersistantState<T>(
key: string,
initialValue: T
): [T, (value: T) => void] {
const [state, setInternalState] = useState<T>(initialValue);
useEffect(() => {
const value = localStorage.getItem(key);
if (!value) return;
setInternalState(JSON.parse(value));
}, [key]);
const setState = (value: T) => {
localStorage.setItem(key, JSON.stringify(value));
setInternalState(value);
};
return [state, setState];
}
Upvotes: 8
Reputation: 101
You can initialize your state by getting the value of local storage. useState hook
accept a function as a parameter.
const [value, setValue] = useState(window.localStorage.getItem('SAVE_SEARCH'))
Now, when your component would render, it will get the value that is on local storage and assign to your state.
But, it would be easier if you would use React Context
to manage global values
.
https://reactjs.org/docs/context.html#when-to-use-context
Upvotes: 2