理解 Svelte 中的 Context(从 React Context 转换) [英] Understanding Context in Svelte (convert from React Context)

查看:55
本文介绍了理解 Svelte 中的 Context(从 React Context 转换)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 ContextAPI 来管理身份验证的 React 应用程序,我正在尝试在 Svelte 中实现类似的功能.[Web 开发简化][1]

I have a react app that uses ContextAPI to manage authentication and I am trying to implement a similar thing in Svelte. [Web Dev Simplified][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 组件中使用,如下所示:

This context is used in other Login.js component like this:

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 上下文?

How do I achieve this in Svelte, particularly the Authenticate context?

我无法在 Svelte 中做很多事情,因为我不知道如何从这里开始.到目前为止,我有 AuthComp.svelte.我不知道我是否在做正确的事情.

I haven't been able to do much in Svelte as I don't know how to proceed from here. So far I have AuthComp.svelte. I don't know if I am doing the right thing.

<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, login, signUp }
    
</script>

<slot value={value}></slot>

推荐答案

从 React Context 迁移到 Svelte

Svelte 和 React 中的上下文可能看起来很相似,但实际上它们的用法不同.因为就核心而言,Svelte 的上下文要受限得多.不过没关系.事实上,它实际上会让您的代码更易于编写和理解.

Migrating from React Context to Svelte

Context in Svelte and React may seem similar, but they are actually used differently. Because at the core, Svelte's context is much more limited. But that's ok. In fact, it actually will make your code simpler to write and understand.

在 Svelte 中,您可以使用更多工具来在您的应用中传递数据(并保持同步),而不仅仅是上下文.每个人几乎都做一件事(让一切都可以预测),而且他们做得很好.其中,您有:

In Svelte, you have more tools at your disposal for passing data round your app (and keeping it in sync) than just context. Each one does pretty much one thing (making everything predictable), and they do it well. Of these, you have:

  • 上下文
  • 商店
  • 道具

作为最近从 React 转向 Svelte 的人,我想我可以帮助解释这些之间的一些差异,并帮助您避免我的一些概念错误.我还将讨论生命周期方法中的一些差异,因为如果您曾经使用 useEffect,您可能会感到很迷茫,因为 Svelte 没有等效的 API.然而,在 Svelte 中将所有内容组合在一起将使一切变得简单.

As someone who's recently switched from React to Svelte, I think I can help explain some of the differences between each of these and help you avoid some of my conceptual mistakes. I'll also go over some differences in life cycle methods, because if you used to use useEffect, you might feel very lost since Svelte doesn't have an equivalent API. Yet combining everything together in Svelte will make everything simple.

Svelte 中的上下文做一件事:将数据从父组件传递给任何子组件(不一定是直接子组件).与 React 不同的是,context 不是响应式的.组件挂载时设置一次,以后不再更新.我们将进入反应性上下文"一秒钟.

Context in Svelte does one thing: pass data from a parent component to any children (not necessarily direct children). Unlike in React, context is not reactive. It is set once when the component mounts, and then will not be updated again. We'll get to "reactive context" in a second.

<!-- parent.svelte -->

<script>
  import { setContext } from 'svelte'

  setContext('myContext', true)
</script>

<!-- child.svelte -->

<script>
  import { getContext } from 'svelte'

  const myContext = getContext('myContext')
</script>

请注意,上下文涉及两件事,一个键和一个值.上下文设置为特定键,然后可以使用该键检索该值.与 React 不同,您不需要导出函数来检索上下文.上下文的键和值都可以是任何东西.如果可以将其保存到变量,则可以将其设置为上下文.您甚至可以将对象用作键!

Notice that context involves two things, a key and a value. Context is set to a specific key, then the value can be retrieved using that key. Unlike React, you do not need to export functions to retrieve the context. Both the key and value for the context can be anything. If you can save it to a variable, you can set it to context. You can even use an object as a key!

如果您的数据需要在应用的多个位置保持同步,那么商店是您的最佳选择.商店是反应性的,这意味着它们可以在创建后更新.与 React 或 Svelte 中的上下文不同,store 不会简单地将数据传递给它们的孩子.应用程序的任何部分都可以创建商店,应用程序的任何部分都可以读取商店.您甚至可以在单独的 JavaScript 文件中在 Svelte 组件之外创建商店.

If you have data that needs to stay in sync in multiple places across your app, stores are the way to go. Stores are reactive, meaning they can be updated after they're created. Unlike context in either React or Svelte, stores don't simply pass data to their children. Any part of your app can create a store, and any part of your app can read the store. You can even create stores outside of Svelte components in separate JavaScript files.

// 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 }

然后在组件内部,您可以订阅商店.

Then inside a component, you can subscribe to the store.

<script>
  import { writableStore } from './mystore'

</script>

{$writableStore}

美元符号订阅商店.现在,每当商店更新时,组件都会自动重新渲染.

The dollar sign subscribes to the store. Now, whenever the store is updated, the component will rerender automatically.

现在我们有了存储和上下文,我们可以创建反应性上下文"(我刚刚编造的一个术语,但它有效).存储很棒,因为它们是反应式的,上下文非常适合将数据传递给子组件.但是我们实际上可以通过上下文向下传递商店.这使上下文具有反应性并且存储范围是.

Now that we have stores and context, we can create "reactive context"(a term I just made up, but it works). Stores are great because they're reactive, and context is great to pass data down to the children components. But we can actually pass a store down through context. This makes the context reactive and the store scoped.

<!-- 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 中可以得到的最接近的.它也少了很多样板!

Now, whenever the store updates in the parent, the child will also update. Stores can of course do much more than this, but if you were looking to replicate React context, this is the closest you can get in Svelte. It's also a lot less boilerplate!

Svelte 没有 useEffect 的等效项.相反,Svelte 具有响应式语句.文档/教程中有很多关于这些的内容,所以我会保持简短.

Svelte does not have an equivalent of useEffect. Instead, Svelte has reactive statements. There's a lot on these in the docs/tutorial, so I'll keep this brief.

// 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 足够聪明,可以找出依赖关系,并且只在需要时运行每个响应式语句.如果你创建了一个依赖循环,编译器会骂你.

Svelte is smart enough to figure out the dependencies and only run each reactive statement as needed. And if you create a dependency cycle, the compiler will yell at you.

这意味着您可以使用反应式语句来更新存储(从而更新上下文).在这里, valueStore 将在每次输入输入时更新.由于此存储通过上下文向下传递,因此任何子级都可以获取输入的当前值.

This means that you can use reactive statements to update stores (and hence update the context). Here, the valueStore will be update on every keystroke to the input. Since this store is passed down through context, any child can then get the current value of the input.

<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 教授双向绑定.

Props

For the most part, props function exactly the same in React and Svelte. There are a few differences because Svelte props can take advantage of two-way binding (not necessary, but possible). That's really a different conversation though, and the tutorial is really good at teaching two-way binding with props.

好的,在完成所有这些之后,让我们看看如何创建身份验证包装器组件.

Ok, now after all of that, let's look at how you'd create an authentication wrapper component.

  • 创建一个授权商店
  • 通过上下文向下传递身份验证存储
  • 使用 Firebase 的 onAuthStateChanged 监听 auth 状态的变化
  • 订阅子进程中的 auth 存储
  • 当父节点被销毁以防止内存泄漏时取消订阅 onAuthStateChanged
  • Create an auth store
  • Pass the auth store down via context
  • Use Firebase's onAuthStateChanged to listen to changes in auth state
  • Subscribe to the auth store in the child
  • Unsubscribe from onAuthStateChanged when the parent is destroyed to prevent memory leaks
<!-- 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 中的 Context(从 React Context 转换)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆