首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SolidJS:基于上下文存储所提供的值更新组件?

SolidJS:基于上下文存储所提供的值更新组件?
EN

Stack Overflow用户
提问于 2022-09-02 06:53:19
回答 1查看 494关注 0票数 2

在React中,所有道具都会自动更新并传播给孩子,这很好,但是速度慢了,并且需要在某个时候进行大量的优化。

因此,我正在用SolidJS构建一个使用Context + createStore模式的应用程序,并且在使用该状态时遇到了问题。

我想要创建AppProvider组件来管理State道具和Dispatch函数。提供者将在appStore上执行所有操作,实现函数,并通过AppContextStateAppContextDispatch提供程序为它们提供服务。

然后,我需要使用这些数据来更新依赖于它的组件。

请看下面的代码:

代码语言:javascript
复制
/// index.tsx
import { render } from 'solid-js/web';
import { AppProvider } from '@/providers/AppProvider';
import App from './App';


render(() => (
    <AppProvider>
        <App />
    </AppProvider>
), document.getElementById('root') as HTMLElement);
代码语言:javascript
复制
/// AppProvider.tsx
import { createContext, useContext, JSX } from 'solid-js';
import { createStore } from 'solid-js/store';

// Interfaces
interface IAppState {
    isConnected: boolean;
    user: { name: string; }
}
interface IAppDispatch {
    connect: () => Promise<void>;
    disconnect: () => Promise<void>;
}


// Initialize
const initialState = {
    isConnected: false,
    user: { name: '' }
}
const initialDispatch = {
    connect: () => {},
    disconnect: () => {}
}


// Contexts
const AppContextState = createContext<IAppState>();
const AppContextDispatch = createContext<IAppDispatch>();
export const useAppState = () => useContext(AppContextState);
export const useAppDispatch = () => useContext(AppContextDispatch);

// Provider
export const AppProvider = (props: { children: JSX.Element }) => {
    const [appStore, setAppStore] = createStore<IAppState>(initialState);

    async function connect() {
        setAppStore("isConnected", true);
        setAppStore("user", "name", 'Chad');
    }

    async function disconnect() {
        setAppStore("isConnected", false);
        setAppStore("user", "name", '');
    }

    return (
        <AppContextState.Provider value={appStore}>
            <AppContextDispatch.Provider value={{ connect, disconnect }}>
                {props.children}
            </AppContextDispatch.Provider>
        </AppContextState.Provider>
    )
}
代码语言:javascript
复制
/// App.tsx
import { useAppState, useAppDispatch } from '@/providers/AppProvider';

export default function App() {
    const { user, isConnected } = useAppState();
    const { connect, disconnect } = useAppDispatch();

    return (
      <Show when={isConnected} fallback={<button onClick={connect}>Connect</button>}>
        <button onClick={disconnect}>Disconnect</button>
        <h3>Your Name: {user.name}</h3>
      </Show>
    )
}

这个组件将显示一个button,它应该运行connect函数并更新isConnected状态,并使<Show>块中的组件可见,但它什么也不做。

我验证了在connect方法中通过记录appStore的数据来更新状态。

当我将组件更改为依赖于user.name而不是isConnected时,它可以工作。

代码语言:javascript
复制
<Show when={user.name} fallback={<button onClick={connect}>Connect</button>}>
    <button onClick={disconnect}>Disconnect</button>
    <h3>Your Name: {user.name}</h3>
</Show>

不过,我的应用程序有许多组件,取决于不同的数据类型,包括boolean,在本例中,有些组件在SolidJS中不起作用。

我想知道我在这里做错了什么,并且理解在组件之间共享状态的最佳方式是什么。我一直在阅读文档并摆弄它,但这个特殊的问题困扰了我几天。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-09 03:01:01

无法跟踪实心中的普通值。

这里的问题是,原始值/变量在实体中不能是反应性的。我们有两种跟踪值访问的方法:通过函数调用和通过属性getter/代理(它们使用遮罩下的信号)。

那么,当您访问商店属性时会发生什么呢?

代码语言:javascript
复制
const state = useAppState();
createEffect(() => {
  console.log(state.isConnected)
})

在这种情况下,属性访问是在效果内进行的,因此,当属性值更新时,它会被跟踪并重新运行。另一方面,在这方面:

代码语言:javascript
复制
const { isConnected } = useAppState();

我们在组件的顶层访问属性(它是untrack编辑的,而不是实体中的反应性)。因此,即使我们在一个具有反应性的上下文中使用这个值(比如when螺旋桨),我们也不能运行任何特殊的底层跟踪来设置更新。

那么,为什么user.name起作用呢?

原因是存储是深度反应的(对于原语、对象和数组),所以

代码语言:javascript
复制
const { user } = useAppState();

这意味着您正在急切地访问用户对象(因此,如果用户属性更改,您将不会得到更新),但是用户对象的属性尚未被访问,它们只能在<Show when={user.name}>中被进一步访问,因此可以跟踪属性访问user.name

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73578823

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档