I want to get 'sample' document in Firestore using getServerSideProps if there is signed user.
Code below doesn't work. It's result is 'can't read'
What should I do? or is there the other way?
export const getServerSideProps = () => {
let currentUser = []
authService.onAuthStateChanged(async user => {
if(user) {
const docRef = dbService.collection('whole_users').doc('sample').get()
await docRef.then((doc) => {
if(doc.exists) {
currentUser.push(doc.data())
}
})
} else {
console.log("can't read")
}
})
return {
props: {currentUser}
}
}
The first:
You call get() without an await. Chaneg your code to this:
export const getServerSideProps = () => {
let currentUser = []
authService.onAuthStateChanged(async user => {
if(user) {
const docRef = dbService.collection('whole_users').doc('sample')
await docRef.get().then((doc) => {
if(doc.exists) {
currentUser.push(doc.data())
}
})
} else {
console.log("can't read")
}
})
return {
props: {currentUser}
}
}
The second: onAuthStateChanged is only for the client side. To access the auth state on the server side you would need to put the auth state into a provider. Here is an example how to do it.
Related
export const login = createAsyncThunk(
"auth/login",
async (inputs:any, thunkAPI) => {
try {
const data = await axios.post("/api/auth/login", inputs);
return { user: data };
} catch (err:any) {
if(err.response){return thunkAPI.rejectWithValue(err.response.data)}
if (err.request) {return thunkAPI.rejectWithValue("Can't Not Access The Server")}
}
}
);
Above it return an error, I would like to know it's there have any solution
I'm a junior dev, so please be easy with me.
My goal is to auth an user anonymously when he open the homepage, then if all went ok, he fetch the data from the real time database, but only if the uid match is ok!
He there are my rules:
{
"rules": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "false",
}
}
}
My database is structured like this https://ibb.co/jkRBCsF
The anonymous sign in is on the context
export const AuthContextProvider = ({ children }: Props) => {
React.useEffect(() => {
signInAnonymously(auth)
.then(() => {
// Signed in..
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ...
});
}, []);
const values = {};
return <AuthContext.Provider value={values}>{children}</AuthContext.Provider>;
};
Then when I open a page for example '/crew' getStaticProps launches fetchPlanetInfo
export const getStaticProps: GetStaticProps = async () => {
const planetInfo = await fetchPlanetsInfo("destinations");
return {
props: {
data: planetInfo,
},
};
};
export function fetchPlanetsInfo(query: string) {
let dataArr: any = [];
try {
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = user.uid;
const databaseCall = ref(db, uid + "/" + query);
onValue(databaseCall, (snapshot) => {
const data = snapshot.val();
dataArr.push(data);
});
} else {
console.log("user is signout");
// User is signed out
// ...
}
});
} catch (error) {
console.log(error);
}
return dataArr.flat();
}
I tried to figure out where is the error but I didn't find out the solution
My problem is that the data is not get from the database. fetchPlanetsInfo return null. I think my rules is written wrong.
I am trying to send my variable 'backEndResponse' with its value from my Express.js backend to my React.js Frontend. I am not quite sure how to send a variable from the backend to the frontend. I have searched around and can't find any good resources. I would appreciate any help.
Express.js Backend
function getcookie(req) {
var authCookie = req.headers.cookie;
if (authCookie = req.headers.cookie) {
try {
return authCookie
.split('; ')
.find(row => row.startsWith('Auth='))
.split('=')[1];
} finally {
if (authCookie = result) {
backEndResponse = true
console.log(backEndResponse);
console.log(result);
} else {
backEndResponse = false
console.log(backEndResponse);
console.log(result);
}
}
} else {
}
}
app.get('/auth', (req, res) => {
getcookie(req)
if (backEndResponse) {
res.json(backEndResponse); // OR json({ message: "Authorised" })
} else {
res.json(backEndResponse); // OR json({ message: "Unauthorised" })
}
});
Frontend React.js
const useAuth = () => {
const [data, setData] = useState();
useEffect(() => {
const fetchAuthData = () => {
const result = axios('http://localhost:5000/auth');
console.log(result)
setData(result.data);
};
fetchAuthData()
}, []);
// Logic to check if backEndResponse is true or false
if (data) {
const authorized = {loggedIn: true}
return authorized && authorized.loggedIn;
} else {
const authorized = {loggedIn: false}
return authorized && authorized.loggedIn;
}
}
const ProtectedRoutes = () => {
const isAuth = useAuth();
return isAuth ? <Outlet/> : <Navigate to="/login" />;
}
You won't be able to send a variable directly, rather you will send a payload in a certain shape that best represents the data suited to the applications needs. To send a response payload in an express route use something like the following:
app.get('/auth', (req, res) => {
// do some logic for `backEndResponse`...
res.json(backEndResponse);
});
If you were intending to provide more information in the response such as HTTP headers differing based on the of backEndResponse then you might consider:
app.get('/auth', (req, res) => {
// do some logic for `backEndResponse`...
// send HTTP Ok if true, otherwise Bad Request
// consider handling 400 and/or 500 errors too
if (backEndResponse) {
res.status(200).json(true); // OR json({ message: "Authorised" })
} else {
res.status(401).json(false); // OR json({ message: "Unauthorised" })
}
});
A component fetching the above endpoint would be similar to:
const MyComponent = () => {
const [data, setData] = useState();
useEffect(() => {
const fetchAuthData = async () => {
const result = await axios('http://localhost:5000/auth');
setData(result.data); // true/false OR { message: "Authorised" }
};
fetchAuthData();
}, []);
// display payload
return (<div>{JSON.stringify(data)}</div>)
}
There is an opportunity to refactor the above into a custom hook should you find the need to reuse the functionality across multiple components.
axios request is async function, so you should do like that,
const useAuth = async () => {
try {
const res = await axios.get('http://localhost:5000/auth', {
withCredentials: true
})
return true
} catch (e) {
return false
}
};
I have a page with a list of objects called stories that displays all my stories in an array. I also have a detail page with displays an individual story.
I want to click on a link on any given story on the list, then it will navigate me to the individual story. I want to use _id as my dynamic part of the URL, as shown in the GraphQL below.
My Graphql
export const listAllStories = () => {
const query = gql`
query StoryEntries($size: Int) {
storyEntries(_size: $size) {
data {
_id
_ts
name
premises{
data{
_id
content
}
}
createdAt
}
}
}
`
return graphQLClient
.request(query, { size: 999 })
.then(({ storyEntries: { data } }) => data)
}
IN MY PAGES API I HAVE
export default async function handler(req, res) {
const handlers = {
GET: async () => {
const storyEntries = await listAllStories()
res.json(storyEntries)
},
}
if (!handlers[req.method]) {
return res.status(405).end()
}
await handlers[req.method]()
}
ON THE STORY LIST PAGE I HAVE
const ENTRIES_PATH = '/api/entries/allStories'
const useEntriesFlow = ({ initialEntries }) => {
const { data: entries } = useSWR(ENTRIES_PATH, {
initialData: initialEntries,
})
const EntryItem = ({ entry }) => (
<>
{entries?.map((entry) => (
{entry.name}
<Link href="/story/[storyId]" as={`/story/${entry._id}`}>
<a>Go</a>
</Link>
))}
</>
)
export const getStaticProps = async () => ({
props: {
initialEntries: await listAllStories(),
},
revalidate: 1,
})
This is fine and works.
**AND THEN ON THE DETAIL PAGE FOR EACH INDIVIDUAL STORY [storyId].js I HAVE **
export default function Story({story}) {
const router = useRouter()
const storyId = router.query.storyId
return(
<>
<h5>hello {story._id}</h5>
</>
)
}
export const getStaticPaths = async () => {
const res = await fetch(`${server}/api/entries/allStories/`);
const { data } = await res.json();
const paths = data.map(story => {
return {
params: { id: story._id.toString() }
}
// trying to get the _id from each story
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
console.log(res)
const { data } = await res.json();
return {
props: { story: data }
}
}
ERROR
TypeError: Cannot read properties of undefined (reading 'map')
QUESTION
All I want to do is click on any story link, then it takes me to the details page, via the _id. I have tried a few things but I'm doing something (or some things) wrong.
Any help will be greatly appreciated.
EDIT AFTER. ERROR I'M GETTING. I'm not able to map my results on getStaticPaths
export const getStaticProps = async (context) => {
const { storyId } = context.query; // Your dynamic page is [storyId].js
const server = "YOUR SERVER VARIABLE";
const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
const { data } = await res.json();
return {
props: { story: data }
}
}
uncomment
const router = useRouter()
const storyId = router.query.storyId
// some helpful links
// https://nextjs.org/docs/basic-features/data-fetching#the-paths-key-required
// https://stackoverflow.com/questions/65783199/error-getstaticpaths-is-required-for-dynamic-ssg-pages-and-is-missing-for-xxx
export const getStaticPaths = async () => {
const server = "http://localhost:3000";
const data = await fetch(`${server}/api/entries/allStories/`).then(res => res.json() )
const paths = data.map(({_id}) => ({
params: { storyId: _id },
}))
return {
paths,
fallback: false
}
}
export const getStaticProps = async (context) => {
const storyId = context.params.storyId; // Your dynamic page is [storyId].js
const server = "http://localhost:3000";
// const res = await fetch(`${server}/api/entries/allStories/${storyId}`);
// trying to get the params._id from each story
// single api call (here)
const res = await fetch(`${server}/api/entries/allStories/`);
// removing const { data } because the data will be returned when calling res.json()
const data = await res.json();
// instead of the calling the single api (just a fix not recommended to access [0] directly )
return {
props: { story: data.filter(story => story._id === storyId)[0] }
}
}
I'm learning react and I'm having difficulty putting data from Firebase into the application state. I use Rebase but I am open to any solution!
still have an error similar to this one :
Thank you for your help !
Here is the code :
class App extends Component {
state = {
user:'',
vampires: {}
}
componentDidMount() {
if(this.state.user === ''){
firebase.auth().onAuthStateChanged(user => {
if(user){
this.handleUserLogin({ user })
this.setVampires({ user })
} else {
console.log('error')
}
})
}
}
setVampires = async (authData) => {
console.log(this.state.user)
await base.fetch(`/${authData.user.uid}/vampires`, { context: this })
.then(data => {
console.log(data)
let vampires = this.state.vampires;
vampires = {..._.cloneDeep(data)};
this.setState({vampires: {vampires}})
})
}
handleUserLogin = async authData => {
this.setState({user: authData.user.uid})
}
Your Firebase data is returned as an Object, with properties VampM5-..... React expects that you pass any repeated data as an array, not as an object.
So you'll need to convert the data from Firebase to an array, for example with:
await base.fetch(`/${authData.user.uid}/vampires`, { context: this })
.then(data => {
vampires = [];
data.forEach((child) => {
vampires.push({ ...child.val(), ".key": child.key });
})
this.setState({ vampires: vampires })
})