I am trying to pass some custom metadata to my firebase firestore, I believe I must pass the metadata I grabbed in my component up to the hook but am unsure how to do so,
my component:
const UploadForm = () => {
const [file, setFile] = useState(null);
const [error, setError] = useState(null);
const [metadata, setMetadata] = useState(null);
const types = ['image/png', 'image/jpeg'];
const changeHandler = (e) => {
let selected = e.target.files[0];
if (selected && types.includes(selected.type)) {
setFile(selected);
setError('');
const pieceName = document.getElementById("pieceName").value;
const pieceDescription = document.getElementById("pieceDescription").value;
const newMetadata = {
customMetaData: {
artName: pieceName,
artDescription: pieceDescription
}
};
setMetadata(newMetadata);
...
export default UploadForm;
& my hook:
const useStorage = (file, metadata) => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
// references
const storageRef = projectStorage.ref(file.name);
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
}, (err) => {
setError(err);
}, async () => {
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt, metadata });
setUrl(url);
});
}, [file, metadata]);
return { progress, url, error };
}
export default useStorage;
I am able to upload to Firebase Storage/firestore no problem but don't know how to feed this extra metadata.
To change the metada just call the updateMetadata on the ref:
const useStorage = (file, metadata) => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
// references
const storageRef = projectStorage.ref(file.name);
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percentage = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percentage);
}, (err) => {
setError(err);
}, async () => {
await storageRef.updateMetadata(metadata)
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt, metadata });
setUrl(url);
});
}, [file, metadata]);
return { progress, url, error };
}
export default useStorage;
You can read more about it here.
Related
I'm fetching an api and want to change useState when the api is returned. However, it simply isn't updating.
Any suggestions?
const fictionApi = "http://localhost:3000/fiction"
const nonFictionApi = "http://localhost:3000/non_fiction"
const [fictionData, setFictionData] = useState(null)
const db = async (url) => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
console.log(data.genre)
}
useEffect(() => {
const db = async (url) => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
console.log(fictionData)
}
db(fictionApi)
}, [])
I think there is something strange with your syntax.
Something like this should work :
const fictionApi = "http://localhost:3000/fiction"
const nonFictionApi = "http://localhost:3000/non_fiction"
export default function Page () {
const [fictionData, setFictionData] = useState(null);
const [url, setUrl] = useState(fictionApi); // ';' very important
useEffect(() => {
(async () => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
})() //Self calling async function
}, [])
}
Moreover, setState is an async process so :
const [fictionData, setFictionData] = useState(null);
setFictionData(true)
console.log(fictionData) //null
So you can use a useEffect to check state :
const [fictionData, setFictionData] = useState(null);
useEffect(()=>{
console.log(fictionData) //true
},[fictionData])
setFictionData(true)
I'm at a loss here. I feel like I've been trying everything, and using the exact methods explained in other posts/tutorials everywhere. I understand that you need to use a cursor and set the first and last visible document so that you can start after the last, in the case of moving forward, and start BEFORE the first, in the case of moving backwards.
In my implementation, going forwards works fine. However, when I utilize the previousPage function, it returns me to the first page, despite setting the 'first visible' document. It returns to the first page even if I've already moved 3 'pages' forward.
Clearly there is something I'm not understanding here..
const PAGE_SIZE = 6;
const [posts, setPosts] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [firstVisible, setFirstVisible] = useState(null);
const [loading, setLoading] = useState(false);
// Initial read to get first set of posts.
useEffect(() => {
const q = query(
collectionGroup(db, "bulletins"),
orderBy("createdAt", "desc"),
limit(PAGE_SIZE)
);
const unsubscribe = onSnapshot(q, (documents) => {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
setLastVisible(documents.docs[documents.docs.length - 1]);
setFirstVisible(documents.docs[0]);
});
return () => unsubscribe();
}, []);
const nextPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
startAfter(lastVisible),
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const previousPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
endBefore(firstVisible),
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const updateState = (documents) => {
if (!documents.empty) {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
}
if (documents?.docs[0]) {
setFirstVisible(documents.docs[0]);
}
if (documents?.docs[documents.docs.length - 1]) {
setLastVisible(documents.docs[documents.docs.length - 1]);
}
};
You should use endAt() instead of endBefore() and also, you should pass the order reference which is the createdAt to the endAt() method. See code below:
const PAGE_SIZE = 6;
const [posts, setPosts] = useState([]);
const [lastVisible, setLastVisible] = useState(null);
const [firstVisible, setFirstVisible] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const q = query(
collectionGroup(db, "bulletins"),
orderBy("createdAt", "desc"),
limit(PAGE_SIZE)
);
const unsubscribe = onSnapshot(q, (documents) => {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
setLastVisible(documents.docs[documents.docs.length - 1]);
setFirstVisible(documents.docs[0]);
});
return () => unsubscribe();
}, []);
const nextPage = async () => {
const postsRef = collectionGroup(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
startAfter(lastVisible.data().createdAt), // Pass the reference
limit(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const previousPage = async () => {
const postsRef = collection(db, "bulletins");
const q = query(
postsRef,
orderBy("createdAt", "desc"),
endAt(firstVisible.data().createdAt), // Use `endAt()` method and pass the reference
limitToLast(PAGE_SIZE)
);
const documents = await getDocs(q);
updateState(documents);
};
const updateState = (documents) => {
if (!documents.empty) {
const tempPosts = [];
documents.forEach((document) => {
tempPosts.push({
id: document.id,
...document.data(),
});
});
setPosts(tempPosts);
}
if (documents?.docs[0]) {
setFirstVisible(documents.docs[0]);
}
if (documents?.docs[documents.docs.length - 1]) {
setLastVisible(documents.docs[documents.docs.length - 1]);
}
};
For more information, See Add a simple cursor to a query.
const DashboardPage = (props) => {
const userData = useSelector((state) => state.userDataReducer.user_record_reducer)
console.log('userdata', userData);
const adm_id = userData.adm_id
const [vistLoader, setVisitLoader] = useState(false)
const drid = localStorage.getItem('drId')
const [dashboard, setDashboard] = useState({})
const [collapsed,setCollapased] = useState(false);
const mr = userData.mrno
useEffect(()=>{
setVisitLoader(true)
const dashboard = getPatientDashboard({mr,drid}).then(res =>{
setDashboard(res)
setTimeout(()=>{
setVisitLoader(false)
}, 500)
}).catch(err =>{
console.log('err',err);
})
},[])
I am trying to implement Spotify player SDK in my react app. But I do not know it is giving me an error that Spotify is undefined. I am trying to implement the script in the useEffect hook in this context file.
This is my context file and trying to set up player SDK in it. Thanks in advance.
import React,{ createContext, useState,useEffect } from 'react'
import { myPlaylist, fetchAnything } from "../../api-fetching/api-fetching"
// Get the hash of the url
const hash = window.location.hash
.substring(1)
.split("&")
.reduce(function(initial, item) {
if (item) {
var parts = item.split("=");
initial[parts[0]] = decodeURIComponent(parts[1]);
}
return initial;
}, {});
window.location.hash = "";
export const MainContext = createContext();
const MainContextProvider = (props) => {
const authEndPoint = 'https://accounts.spotify.com/authorize?';
// Replace with your app's client ID, redirect URI and desired scopes
const clientId = "5c4e46e8acf24w794ru325qi535fw5325hsakf22be91378ff14";
let redirectUri = "";
if(process.env.NODE_ENV === "development") {
redirectUri += "http://localhost:3000/";
}
const scopes = [
"streaming", "user-read-email", "user-read-private",
"user-read-currently-playing",
"user-read-playback-state",
"user-library-read",
"playlist-read-collaborative",
"playlist-read-private"
];
const [token, setToken] = useState(null);
const [scriptLoading, setScriptLoading] = useState(true);
const [currentUser, setCurrentUser] = useState(null);
const [discover, setDiscover] = useState(null);
const [discoverPlaylist, setDiscoverPlaylist] = useState(null);
const [discoverPlaylistTracks, setDiscoverPlaylistTracks] = useState(null);
const [userPlaylist, setUserPlaylist] = useState(null);
const [ userPlaylistTracks ,setUserPlaylistTracks] = useState(null);
const [artistInfo, setArtistInfo] = useState(null);
const [albumTracks, setAlbumTracks] = useState(null);
const [newReleases, setNewReleases] = useState(null);
const [newReleasesTracks, setNewReleasesTracks] = useState(null);
const [searchResult, setSearchResult] = useState(null);
const [searchValue, setSearchValue] = useState("");
const [playlistTracks, setPlaylistTracks] = useState(null);
useEffect(() => {
let _token = hash.access_token;
setToken(_token);
fetchAnything(token, "https://api.spotify.com/v1/me", setCurrentUser);
if(scriptLoading){
const script = document.createElement("script");
script.src = "https://sdk.scdn.co/spotify-player.js";
script.async = true;
script.defer = true;
document.body.appendChild(script);
setScriptLoading(false);
}
window.onSpotifyWebPlaybackSDKReady = () => {
const player = new Spotify.Player({
name: 'Web Playback SDK Quick Start Player',
getOAuthToken: cb => { cb(token); }
});
// Error handling
player.addListener('initialization_error', ({ message }) => { console.error(message); });
player.addListener('authentication_error', ({ message }) => { console.error(message); });
player.addListener('account_error', ({ message }) => { console.error(message); });
player.addListener('playback_error', ({ message }) => { console.error(message); });
// Playback status updates
player.addListener('player_state_changed', state => { console.log(state); });
// Ready
player.addListener('ready', ({ device_id }) => {
console.log('Ready with Device ID', device_id);
});
// Not Ready
player.addListener('not_ready', ({ device_id }) => {
console.log('Device ID has gone offline', device_id);
});
// Connect to the player!
player.connect();
};
}, [token])
useEffect(() => {
if(currentUser){
myPlaylist(token, setUserPlaylist, currentUser.id);
}
}, [currentUser, token])
return (
<MainContext.Provider
value={{ currentUser,playlistTracks, setPlaylistTracks ,searchValue, setSearchValue,searchResult, setSearchResult,newReleasesTracks, setNewReleasesTracks ,newReleases, setNewReleases ,albumTracks, setAlbumTracks,artistInfo, setArtistInfo,discoverPlaylistTracks, setDiscoverPlaylistTracks,userPlaylistTracks, setUserPlaylistTracks, userPlaylist,discoverPlaylist,setDiscoverPlaylist,discover,setDiscover, token,setToken, authEndPoint, clientId, redirectUri, scopes }}>
{props.children}
</MainContext.Provider>
)
}
export default MainContextProvider
You must refer to the Player through a global object:
window.onSpotifyWebPlaybackSDKReady = () => {
const player = new window.Spotify.Player({
name: "Carly Rae Jepsen Player",
getOAuthToken: (callback) => {
callback("access token here");
},
volume: 0.5,
});
};
I am create custom hook that fetch requests network.I want to call custom hook when form submit button clicked but depending on hook rules i can't do that. how to can implement this scenario?
this custom hook:
const useRequest = (url, method, dependencies, data = null) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const res = await request[method](url, data);
setResponse(res);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
};
fetchData();
}, dependencies);
return { response, error, loading };
};
Move fetchData function out of useEffect and export it:
const useRequest = (url, method, dependencies, data = null) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
try {
const res = await request[method](url, data);
setResponse(res);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, dependencies);
return { response, error, loading, fetchData };
};
Than when you can call it anywhere in your code.