ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto

add useCallback to hook-returned functions

byarielm.fyi d1c5e9a1 cf5ff83a

verified
Changed files
+26 -24
src
+4 -4
src/hooks/useFollows.ts
··· 1 - import { useState } from "react"; 2 import { apiClient } from "../lib/api/client"; 3 import { FOLLOW_CONFIG } from "../config/constants"; 4 import { getAtprotoApp } from "../lib/utils/platform"; ··· 15 const [isFollowing, setIsFollowing] = useState(false); 16 const [isCheckingFollowStatus, setIsCheckingFollowStatus] = useState(false); 17 18 - async function followSelectedUsers( 19 onUpdate: (message: string) => void, 20 - ): Promise<void> { 21 if (!session || isFollowing) return; 22 23 const destinationApp = getAtprotoApp(destinationAppId); ··· 156 } finally { 157 setIsFollowing(false); 158 } 159 - } 160 161 return { 162 isFollowing,
··· 1 + import { useState, useCallback } from "react"; 2 import { apiClient } from "../lib/api/client"; 3 import { FOLLOW_CONFIG } from "../config/constants"; 4 import { getAtprotoApp } from "../lib/utils/platform"; ··· 15 const [isFollowing, setIsFollowing] = useState(false); 16 const [isCheckingFollowStatus, setIsCheckingFollowStatus] = useState(false); 17 18 + const followSelectedUsers = useCallback(async ( 19 onUpdate: (message: string) => void, 20 + ): Promise<void> => { 21 if (!session || isFollowing) return; 22 23 const destinationApp = getAtprotoApp(destinationAppId); ··· 156 } finally { 157 setIsFollowing(false); 158 } 159 + }, [session, searchResults, setSearchResults, destinationAppId, isFollowing]); 160 161 return { 162 isFollowing,
+22 -20
src/hooks/useSearch.ts
··· 1 - import { useState } from "react"; 2 import { apiClient } from "../lib/api/client"; 3 import { SEARCH_CONFIG } from "../config/constants"; 4 import type { SearchResult, SearchProgress, AtprotoSession } from "../types"; ··· 15 new Set(), 16 ); 17 18 - async function searchAllUsers( 19 resultsToSearch: SearchResult[], 20 onProgressUpdate: (message: string) => void, 21 onComplete: () => void, 22 followLexicon?: string, 23 - ) { 24 if (!session || resultsToSearch.length === 0) return; 25 26 setIsSearchingAll(true); ··· 133 `Search complete! Found ${totalFound} matches out of ${totalSearched} users searched.`, 134 ); 135 onComplete(); 136 - } 137 138 - function toggleMatchSelection(resultIndex: number, did: string) { 139 setSearchResults((prev) => { 140 // Only update the specific item instead of mapping entire array 141 const newResults = [...prev]; ··· 151 newResults[resultIndex] = { ...result, selectedMatches: newSelectedMatches }; 152 return newResults; 153 }); 154 - } 155 156 - function toggleExpandResult(index: number) { 157 setExpandedResults((prev) => { 158 const next = new Set(prev); 159 if (next.has(index)) next.delete(index); 160 else next.add(index); 161 return next; 162 }); 163 - } 164 165 - function selectAllMatches(onUpdate: (message: string) => void) { 166 - setSearchResults((prev) => 167 - prev.map((result) => { 168 const newSelectedMatches = new Set<string>(); 169 if (result.atprotoMatches.length > 0) { 170 newSelectedMatches.add(result.atprotoMatches[0].did); ··· 173 ...result, 174 selectedMatches: newSelectedMatches, 175 }; 176 - }), 177 - ); 178 179 - const totalToSelect = searchResults.filter( 180 - (r) => r.atprotoMatches.length > 0, 181 - ).length; 182 - onUpdate(`Selected ${totalToSelect} top matches`); 183 - } 184 185 - function deselectAllMatches(onUpdate: (message: string) => void) { 186 setSearchResults((prev) => 187 prev.map((result) => ({ 188 ...result, ··· 190 })), 191 ); 192 onUpdate("Cleared all selections"); 193 - } 194 195 const totalSelected = searchResults.reduce( 196 (total, result) => total + (result.selectedMatches?.size || 0),
··· 1 + import { useState, useCallback } from "react"; 2 import { apiClient } from "../lib/api/client"; 3 import { SEARCH_CONFIG } from "../config/constants"; 4 import type { SearchResult, SearchProgress, AtprotoSession } from "../types"; ··· 15 new Set(), 16 ); 17 18 + const searchAllUsers = useCallback(async ( 19 resultsToSearch: SearchResult[], 20 onProgressUpdate: (message: string) => void, 21 onComplete: () => void, 22 followLexicon?: string, 23 + ) => { 24 if (!session || resultsToSearch.length === 0) return; 25 26 setIsSearchingAll(true); ··· 133 `Search complete! Found ${totalFound} matches out of ${totalSearched} users searched.`, 134 ); 135 onComplete(); 136 + }, [session]); 137 138 + const toggleMatchSelection = useCallback((resultIndex: number, did: string) => { 139 setSearchResults((prev) => { 140 // Only update the specific item instead of mapping entire array 141 const newResults = [...prev]; ··· 151 newResults[resultIndex] = { ...result, selectedMatches: newSelectedMatches }; 152 return newResults; 153 }); 154 + }, []); 155 156 + const toggleExpandResult = useCallback((index: number) => { 157 setExpandedResults((prev) => { 158 const next = new Set(prev); 159 if (next.has(index)) next.delete(index); 160 else next.add(index); 161 return next; 162 }); 163 + }, []); 164 165 + const selectAllMatches = useCallback((onUpdate: (message: string) => void) => { 166 + setSearchResults((prev) => { 167 + const updated = prev.map((result) => { 168 const newSelectedMatches = new Set<string>(); 169 if (result.atprotoMatches.length > 0) { 170 newSelectedMatches.add(result.atprotoMatches[0].did); ··· 173 ...result, 174 selectedMatches: newSelectedMatches, 175 }; 176 + }); 177 178 + const totalToSelect = updated.filter( 179 + (r) => r.atprotoMatches.length > 0, 180 + ).length; 181 + onUpdate(`Selected ${totalToSelect} top matches`); 182 + 183 + return updated; 184 + }); 185 + }, []); 186 187 + const deselectAllMatches = useCallback((onUpdate: (message: string) => void) => { 188 setSearchResults((prev) => 189 prev.map((result) => ({ 190 ...result, ··· 192 })), 193 ); 194 onUpdate("Cleared all selections"); 195 + }, []); 196 197 const totalSelected = searchResults.reduce( 198 (total, result) => total + (result.selectedMatches?.size || 0),