如何解决理解 Svelte 中的 Context从 React Context 转换 在上下文中使用商店在“useEffect”中使用“reactive context”
我有一个使用 ContextAPI 来管理身份验证的 React 应用程序,我正在尝试在 svelte 中实现类似的功能。 [Web 开发简化][1]
在 Authenticate.js
我有这个:
import React,{ useContext,useState,useEffect } from "react"
import { auth } from "../firebase"
const AuthCt = React.createContext()
export function Auth() {
return useContext(AuthCt)
}
export function AuthComp({ children }) {
const [currentUser,setCurrentUser] = useState()
const [loading,setLoading] = useState(true)
function login(email,password) {
return auth.signInWithEmailAndPassword(email,password)
}
function logout() {
return auth.signOut()
}
useEffect(() => {
const unmount = auth.onAuthStateChanged(user => {
setCurrentUser(user)
setLoading(false)
})
return unmount
},[])
const value = {
currentUser,login,signup
}
return (
<AuthCt.Provider value={value}>
{!loading && children}
</AuthCt.Provider>
)
}
此上下文在其他 Login.js
组件中使用,如下所示:
import { Auth } from "./Authenticate"
const Login = () => {
const { currentUser,login } = Auth()
在 App.js
中,我有:
import { AuthComp } from "./Authenticate";
function App() {
return (
<AuthComp>
<div> All others go here </div>
</AuthComp>
);
}
我如何在 svelte 中实现这一点,尤其是 Authenticate
上下文?
我无法在 svelte 中做很多事情,因为我不知道如何从这里开始。到目前为止,我有 AuthComp.svelte
。我不知道我是否在做正确的事情。
<script>
import { getContext,setContext } from 'svelte';
import { auth } from '../firebase';
import { writable } from 'svelte/store';
let Auth = getContext('AuthCt')
setContext('Auth',Auth)
let currentUser;
let loading = true;
const unmount = auth.onAuthStateChanged(user => {
currentUser = user;
loading = false
});
function login(email,password) {
return auth.signInWithEmailandPassWord(email,password)
}
function logout() {
return auth.signOut()
}
const value = { currentUser,signUp }
</script>
<slot value={value}></slot>
解决方法
从 React Context 迁移到 Svelte
Svelte 和 React 中的上下文可能看起来很相似,但实际上它们的用法不同。因为就核心而言,Svelte 的上下文要受限得多。不过没关系。事实上,它实际上会让您的代码更易于编写和理解。
在 Svelte 中,您可以使用更多工具来在您的应用中传递数据(并保持同步),而不仅仅是上下文。每个人几乎都做一件事(让一切都可以预测),而且他们做得很好。其中,您有:
- 上下文
- 商店
- 道具
作为最近从 React 转向 Svelte 的人,我想我可以帮助解释这些之间的一些差异,并帮助您避免我的一些概念错误。我还将讨论生命周期方法的一些差异,因为如果您曾经使用 useEffect
,您可能会感到很迷茫,因为 Svelte 没有等效的 API。然而,在 Svelte 中将所有内容组合在一起将使一切变得简单。
上下文
Svelte 中的上下文做一件事:将数据从父组件传递给任何子组件(不一定是直接子组件)。与 React 不同的是,context 不是响应式的。组件挂载时设置一次,以后不再更新。稍后我们将进入“反应式上下文”。
<!-- parent.svelte -->
<script>
import { setContext } from 'svelte'
setContext('myContext',true)
</script>
<!-- child.svelte -->
<script>
import { getContext } from 'svelte'
const myContext = getContext('myContext')
</script>
请注意,上下文涉及两件事,一个键和一个值。上下文设置为特定键,然后可以使用该键检索该值。与 React 不同,您不需要导出函数来检索上下文。上下文的键和值都可以是任何东西。如果可以将其保存到变量,则可以将其设置为上下文。您甚至可以将对象用作键!
商店
如果您的数据需要在应用的多个位置保持同步,那么商店是您的最佳选择。商店是反应性的,这意味着它们可以在创建后更新。与 React 或 Svelte 中的上下文不同,store 不会简单地将数据传递给它们的孩子。应用程序的任何部分都可以创建商店,应用程序的任何部分都可以读取商店。您甚至可以在单独的 JavaScript 文件中在 Svelte 组件之外创建商店。
// mystore.ts
import { writable } from 'svelte/store'
// 0 is the initial value
const writableStore = writable(0)
// set the new value to 1
const writableStore.set(1)
// use `update` to set a new value based on the previous value
const writableStore.update((oldValue) => oldValue + 1)
export { writableStore }
然后在组件内部,您可以订阅商店。
<script>
import { writableStore } from './mystore'
</script>
{$writableStore}
美元符号订阅商店。现在,每当商店更新时,组件都会自动重新渲染。
在上下文中使用商店
现在我们有了存储和上下文,我们可以创建“反应性上下文”(我刚刚编造的一个术语,但它有效)。存储很棒,因为它们是反应式的,上下文非常适合将数据传递给子组件。但是我们实际上可以通过上下文向下传递商店。这使得上下文具有反应性并且存储范围是。
<!-- parent.svelte -->
<script>
import { setContext } from 'svelte'
import { writable } from 'svelte/store'
const writableStore = writable(0)
setContext('myContext',writableStore)
</script>
<!-- child.svelte -->
<script>
import { getContext } from 'svelte'
const myContext = getContext('myContext')
</script>
{$myContext}
现在,每当父级中的 store 更新时,子级也会更新。 Stores 当然可以做的远不止这些,但如果你想复制 React 上下文,这是你在 Svelte 中可以得到的最接近的。它也少了很多样板!
在“useEffect”中使用“reactive context”
Svelte 没有 useEffect
的等价物。相反,Svelte 具有响应式语句。文档/教程中有很多关于这些的内容,所以我会保持简短。
// doubled will always be twice of single. If single updates,doubled will run again.
$: doubled = single * 2
// equivalent to this
let single = 0
const [doubled,setDoubled] = useState(single * 2)
useEffect(() => {
setDoubled(single * 2)
},[single])
Svelte 足够聪明,可以找出依赖关系,并且只在需要时运行每个响应式语句。如果你创建了一个依赖循环,编译器会骂你。
这意味着您可以使用反应式语句来更新存储(从而更新上下文)。在这里,valueStore
将在每次输入时更新。由于此存储通过上下文向下传递,因此任何子级都可以获取输入的当前值。
<script>
import { setContext } from 'svelte'
import { writable } from 'svelte/store'
// this value is bound to the input's value. When the user types,this variable will always update
let value
const valueStore = writable(value)
setContext('inputContext',valueStore)
$: valueStore.set(value)
</script>
<input type='text' bind:value />
道具
在大多数情况下,props 在 React 和 Svelte 中的功能完全相同。有一些不同之处,因为 Svelte 道具可以利用双向绑定(不是必需的,但可能)。不过,那确实是一次不同的对话,而且本教程非常擅长使用 props 教授双向绑定。
Svelte 中的身份验证
好的,在完成所有这些之后,让我们看看如何创建身份验证包装器组件。
- 创建一个授权商店
- 通过上下文向下传递身份验证存储
- 使用 Firebase 的
onAuthStateChanged
监听身份验证状态的变化 - 订阅子进程中的 auth 存储
- 在父级被销毁时取消订阅
onAuthStateChanged
以防止内存泄漏
<!-- parent.svelte -->
<script>
import { writable } from 'svelte/store'
import { onDestroy,setContext } from 'svelte'
import { auth } from '../firebase'
const userStore = writable(null)
const firebaseUnsubscribe = auth.onAuthStateChanged((user) => {
userStore.set(user)
})
const login = (email,password) => auth.signInWithEmailandPassWord(email,password)
const logout = () => auth.sinnOut()
setContext('authContext',{ user: userStore,login,logout })
onDestroy(() => firebaseUnsubscribe())
</script>
<slot />
<!-- child.svelte -->
<script>
import { getContext } from 'svelte'
const { login,logout,user } = getContext('authContext')
</script>
{$user?.displayName}
,
在 Svelte 中,上下文在父组件中使用 setContext(key,value)
设置,子组件可以使用 value
访问 getContext(key)
对象。有关详细信息,请参阅 the docs。
在您的情况下,上下文将像这样使用:
<script>
import { getContext,setContext } from 'svelte';
import { auth } from '../firebase';
import { writable } from 'svelte/store';
// you can initialize this to something else if you want
let currentUser = writable(null)
let loading = true
// maybe you're looking for `onMount` or `onDestroy`?
const unmount = auth.onAuthStateChanged(user => {
currentUser.set(user)
loading = false
});
function login(email,password) {
return auth.signInWithEmailandPassWord(email,password)
}
function logout() {
return auth.signOut()
}
const value = { currentUser,signUp }
setContext('Auth',value)
</script>
{#if !loading}
<slot></slot>
{/if}
这里,currentUser
、login
和 signup
(不确定它来自哪里?)被设置为带有 setContext()
的上下文。要使用此上下文,您可能会有以下内容:
<!-- App -->
<AuthComp>
<!-- Some content here -->
<Component />
</AuthComp>
<!-- Component.svelte -->
<script>
import { getContext } from 'svelte'
const { currentUser,signup } = getContext('Auth')
// you can subscribe to currentUser with $currentUser
</script>
<div>some content</div>
如文档中所写,上下文非反应性,因此 currentUser
首先转换为 store,因此它可以在子代中变为 subscribed to。至于 useEffect
,Svelte 具有 lifecycle functions,您可以使用它在不同点运行代码,例如 onMount
或 onDestroy
。
如果您是 Svelte 的新手,他们的 tutorial 非常全面,提供了大量示例供您参考。
希望这有帮助!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。