将 Firebase 与 React Hooks 结合使用
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
本教程演示如何在 React 应用中使用Hooks,以便更好地集成 Firebase 身份验证和 Firestore 数据获取。在开始之前,建议您对Hooks、Firebase身份验证和Firestore有一定的了解。教程最后,我们将构建示例应用Julienne.app中的一些 Hooks 。
监控身份验证
结合使用 Hooks 和Context,可以轻松地在 React 应用的任何位置访问用户会话。我们可以将用户会话存储在 Context 中,并将该 Context 传递给子组件。这些子组件随后可以使用 Hooks 来访问会话对象。
首先,构建我们的背景。
const userContext = React.createContext({
user: null,
})
我们为上下文提供的默认值包含一个空的会话对象。当我们使用 Firebase 监控会话更改时,此值将会改变。
接下来,我们将创建一个钩子,以便访问我们的上下文。
export const useSession = () => {
const { user } = useContext(userContext)
return user
}
最后,我们来创建一个钩子来监控 Firebase 身份验证状态。这个钩子会创建一个状态,该状态使用useState回调函数来判断用户会话是否已存在。回调函数的作用在于,它允许组件仅在首次挂载时才初始化状态值。
接下来,我们使用一个effect监控身份验证更改的函数。当您使用 Firebase 提供的众多登录方法之一触发登录(或注销)时,该onChange函数将使用当前的身份验证状态进行调用。
最后,我们返回身份验证状态。
export const useAuth = () => {
const [state, setState] = React.useState(() => { const user = firebase.auth().currentUser return { initializing: !user, user, } })
function onChange(user) {
setState({ initializing: false, user })
}
React.useEffect(() => {
// listen for auth state changes
const unsubscribe = firebase.auth().onAuthStateChanged(onChange)
// unsubscribe to the listener when unmounting
return () => unsubscribe()
}, [])
return state
}
然后,我们可以在应用程序的顶层使用此钩子,并使用我们的上下文提供程序将用户会话提供给子组件。
function App() {
const { initializing, user } = useAuth()
if (initializing) {
return <div>Loading</div>
}
return (
<userContext.Provider value={{ user }}> <UserProfile /> </userContext.Provider> )
}
最后,在子组件中,我们可以使用useSession钩子来访问用户会话。
function UserProfile() {
const { user } = useSession() return <div>Hello, {user.displayName}</div>
}
实际上,登录或注销完全不需要使用钩子函数。只需在事件处理程序中调用firebase.auth().signOut()各种登录方法即可。
获取文档
使用 Firestore 时,Hooks 可以用来监控单个文档查询。在这个例子中,我们希望在收到 `<recipe>` 参数时获取一个菜谱id。我们需要为组件提供 ` <recipe>` error、loading`<recipe>` 和recipe`<state>` 参数。
function useRecipe(id) {
// initialize our default state
const [error, setError] = React.useState(false) const [loading, setLoading] = React.useState(true) const [recipe, setRecipe] = React.useState(null)
// when the id attribute changes (including mount)
// subscribe to the recipe document and update
// our state when it changes.
useEffect(
() => {
const unsubscribe = firebase.firestore().collection('recipes') .doc(id).onSnapshot( doc => { setLoading(false) setRecipe(doc) }, err => { setError(err) } )
// returning the unsubscribe function will ensure that
// we unsubscribe from document changes when our id
// changes to a different value.
return () => unsubscribe()
},
[id]
)
return {
error,
loading,
recipe,
}
}
获取集合
获取集合的过程非常相似,但我们订阅的是文档集合。
function useIngredients(id) {
const [error, setError] = React.useState(false)
const [loading, setLoading] = React.useState(true)
const [ingredients, setIngredients] = React.useState([])
useEffect(
() => {
const unsubscribe = firebase
.firestore()
.collection('recipes')
.doc(id)
.collection('ingredients') .onSnapshot( snapshot => { const ingredients = [] snapshot.forEach(doc => { ingredients.push(doc) }) setLoading(false) setIngredients(ingredients) }, err => { setError(err) } )
return () => unsubscribe()
},
[id]
)
return {
error,
loading,
ingredients,
}
}
如果你计划在整个应用程序中使用 Firebase Hooks,我建议你了解一下react-firebase-hooks。它提供了一些有用的辅助函数,使我们能够复用上面编写的部分逻辑。
如需查看使用 Firebase、React 和 Typescript 构建的完整应用程序示例,请查看Julienne。
(本文发布在我的博客 benmcmahen.com 上。点击此处即可在线阅读。)
文章来源:https://dev.to/bmcmahen/using-firebase-with-react-hooks-21ap