I have constructed a singleton class as an external state management solution for my ReactJS app. My issue is that the function parameters inside components do not get updated.
export class ProductSearchStore {
private static instance: ProductSearchStore;
searchTerm: string = "";
subscribers: Set<() => void> = new Set();
private constructor() {}
public static getInstance(): ProductSearchStore {
if (!ProductSearchStore.instance) {
ProductSearchStore.instance = new ProductSearchStore();
}
return ProductSearchStore.instance;
}
public subscribe = (cb: () => void): (() => void) => {
this.subscribers.add(cb);
return () => {
this.subscribers.delete(cb);
};
};
public set = (value: Partial<ProductSearchStore>): void => {
this.searchTerm = value.searchTerm ?? this.searchTerm;
this.subscribers.forEach((cb) => cb());
};
public get = (): string => {
return this.searchTerm;
};
}
export function useProductSearchStore(): [string, (term: string) => void] {
const productSearchStore = useRef<ProductSearchStore>(ProductSearchStore.getInstance());
const [searchTerm, setSearchTerm] = useState<string>("");
function updateSearchTerm(): void {
productSearchStore.current.set({ searchTerm: term });
}
useEffect(() => {
const unsubscribe = productSearchStore.current.subscribe(() => {
setSearchTerm(productSearchStore.current!.get());
});
return () => {
unsubscribe();
};
}, []);
return [searchTerm, updateSearchTerm];
}
Here is the implementation inside a React component:
const [searchTerm, setSearchTerm] = useProductSearchStore();
function updateSearchTerm(term: string) {
console.log("searchTerm", searchTerm);
}
useEffect(() => {
console.log("searchTerm", searchTerm);
}, [searchTerm]);
The useEffect
function outputs the latest searchTerm
correctly but the updateSearchTerm
function is not it always returns an empty string.