I am making a chat application with Firebase 9 and React 18.
I run into a problem while making use of the OutsideClickHandler package.
In the SearchUsers.jsx component, I have a search-box:
import OutsideClickHandler from 'react-outside-click-handler';
export default function SearchUsers({ setIsSearch, setSearchQuery }) {
const sendSearchQuery = async (e) => {
if (e.target.value.length > 2) {
setIsSearch(true);
setSearchQuery(e.target.value);
} else {
if(!e.target.value.length){
setIsSearch(false);
}
setSearchQuery("");
}
}
const handleOutsideClick = () => {
setTimeout(setIsSearch(false), 200);
}
return (
<OutsideClickHandler onOutsideClick={ handleOutsideClick }>
<div className="search-box">
<form className="d-flex">
<button className="search-button text-muted">
<FontAwesomeIcon icon="fa-search"/>
</button>
<input type="search" placeholder="Find people to talk to" className="search-field w-100" onFocus={() => setIsSearch(true)} onChange={ sendSearchQuery } />
</form>
</div>
</OutsideClickHandler>
);
}
The above sets the variable isSearch to false when the user clicks outside the search-box.
In UsersList.jsx I have:
import { useLocation } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { or, collection, query, limit, where, getDocs } from "firebase/firestore";
import { db } from "../../firebaseConfig";
import ConversationsList from './ConversationsList';
import UserItem from './UserItem';
export default function UsersList({ isSearch, searchQuery }) {
const location = useLocation();
const [users, setUsers] = useState([]);
const [err, setErr] = useState(false);
const searchUsers = async () => {
const q = query(collection(db, "users"),
or(
where('firstName', '==', searchQuery),
where('lastName', '==', searchQuery),
where('email', '==', searchQuery)
), limit(10));
try {
const querySnapshot = await getDocs(q);
const usersArray = [];
querySnapshot.forEach(doc => {
if (doc.data() !== null) {
usersArray.push(doc.data());
}
});
setUsers(usersArray);
} catch (error) {
setErr(true);
}
}
const selectUser = (user) => {
console.log(user);
}
const usersList = () => {
return users.map(user => (
<UserItem
key={user.uid}
user={user}
selectUser={selectUser}
/>
))
}
useEffect(() => {
searchUsers();
}, [location, setUsers, searchUsers])
return (
<>
{isSearch ?
<div className="chat-users">
{!users.length ? <p className="m-0 text-center text-danger">No users found</p> :
<PerfectScrollbar>
<ul className="list list-unstyled m-0 d-table w-100">
{usersList()}
</ul>
</PerfectScrollbar>
}
</div> : <ConversationsList />
}
</>
);
}
The goal
The goal is to set the isSearch variable to false upon clicking outside the search-box with a delay, so that I can get the selected user (in the Crome console, for now, as seen below):
const selectUser = (user) => {
console.log(user);
}
The problem
There is no delay, even though I do use setTimeout. Before introducing the OutsideClickHandler package into the app, I did get the user object, but not anymore. And I need it.
Question:
How can I get the user object while keeping the OutsideClickHandler package?
>Solution :
setTimeout function expects a function as its first argument, but you’re directly calling setIsSearch(false). As a result it’s immediately executed, without any delay. So you need to pass a function to setTimeout:
const handleOutsideClick = () => {
setTimeout(() => setIsSearch(false), 200);
};