Stencil.js 和 RTK 查询:避免无限回调

问题描述 投票:0回答:1

我正在尝试确定我是否正在使用 RTKQuery 来使我的 Stencil.js 组件的状态与数据库正确同步。

我的行为是我的组件将使用 RTK 查询和 store.dispatch() 获取数据并将其分配给本地状态。然后用户改变组件,这也是通过 store dispatch() 函数使用 rtk 查询 api 发出的请求。

我设法让我的组件重新呈现的唯一方法是使用

componentWIllLoad()
生命周期方法订阅商店并传入一个获取函数
store.dispatch(api.endpoints.fetchFunction.initiate())
作为回调。

虽然这可以很好地保持状态同步,但它确实会导致 fetchFunction() 之间的无限调用循环,该 fetchFunction() 作为动作分派并调用订阅,然后调用 fetchFunction() 等等。这可以通过订阅中的一个简单的 console.log() 语句看出。

虽然这种行为不是世界末日,但感觉不是很优雅。可以改进吗?

RTK 查询设置: 我有一个 API:

- api.ts
export const oracleApi = createApi({
 reducerPath: 'oracleApi',
 baseQuery: fetchBaseQuery({
 baseUrl: 'http://localhost:8000/api/v1/',
 prepareHeaders: async headers => {
 try {
 console.log(await localForage.getItem('CHLJWT'))
 const token = await getToken(localForage)
 if (token) {
 headers.set('Authorization', `CHLJWT ${token.access}`)
        }
 console.log('HEADERS Authorization: ', headers.get('Authorization'))
 return headers
      } catch (error) {
 console.error('Login Required: ', error)
      }
    },
  }),
 tagTypes: ['Spaces', 'Auth', 'Users', 'Documents', 'Figures', 'Organisations'],
 endpoints: build => ({
 //Auth
 login: build.mutation<CHLTokenData, CHLLoginData>({
 query(body) {
 return {
 url: `auth/jwt/create/`,
 method: 'POST',
 body,
        }
      },
 invalidatesTags: [{ type: 'Auth', id: 'LIST' }],
    }),

redux 商店:

- store.ts



export const store = configureStore({
  reducer: {
    // Add the generated reducer as a specific top-level slice
    [api.reducerPath]: api.reducer,
  },
  // Adding the api middleware enables caching, invalidation, polling,
  // and other useful features of `rtk-query`.
  middleware: getDefaultMiddleware => getDefaultMiddleware().concat(api.middleware),
})

// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch)

和一个 index.ts 文件来组合它们

-index.ts


export const api = {
  //Spaces
  getSpace: async (id: SpaceId) => {
    try {
      const space = await store.dispatch(api.endpoints.getSpace.initiate(id))
      return space
    } catch (error) {
      console.error(error)
    }
  },
  getSpaces: async (data?) => {
    try {
      const spaces = await store.dispatch(api.endpoints.getSpaces.initiate())
      return spaces
    } catch (error) {
      console.error(error)
    }
  },

  deleteSpace: async (id: SpaceId) => {
    try {
      await store.dispatch(api.endpoints.deleteSpace.initiate(id))
    } catch (error) {
      console.error(error)
    }
  },

  createSpace: async data => {
    try {
      const res = await store.dispatch(api.endpoints.addSpace.initiate(data))
      return res
    } catch (error) {
      console.error(error)
    }
  },

  updateSpace: async (space, data) => {
    try {
      const id = space.id
      const res = await store.dispatch(api.endpoints.updateSpace.initiate({ id, ...data }))
      return res
    } catch (error) {
      console.error(error)
    }
  },

}

最后,我有一个 stencil.js 组件

import { store } from 'server_state/store'
import { api } from 'server_state/index'
@Component({
  tag: 'app-topbar',
  styleUrl: 'app-topbar.css',
})
export class AppTopbar {
  private unsubscribe: () => void

  @State() space: Space


  async componentWillLoad() {
    this.spaceId = Router.activePath.slice(8, 44) as SpaceId

    this.unsubscribe = store.subscribe(async () => {
      await this.loadData()
    })
    await this.loadData()
  }
  disconnectedCallback() {
    this.unsubscribe()
  }

  async loadData() {
    try {
      console.log('Loading data:app-topbar')
      api.getSpace(this.spaceId)
      this.space = spaceResult.data
    } catch (error) {
      console.error(error)
    }
  }

  render() {
///
   }
}

随着改进这个模式,我特别感兴趣的是是否可以使用 redux 的 createApi 来获取数据而不调用 store.subscribe() 回调。

谢谢!

redux state rtk-query stenciljs stencil-component
1个回答
0
投票

这真的分为3个问题:

  • Redux 商店如何宣布它已更新?
  • UI 组件如何知道 Redux store 是否更新以及 this 组件是否需要更新?
  • Stencil 具体如何与 Redux store 交互?

对于前两个主题,请参阅我的博客文章React-Redux 的历史和实现 中的长篇解释和谈话深入研究 React-Redux,但 TL;DR 可以在我们的文档中看到 https://redux.js.org/tutorials/fundamentals/part-5-ui-react#integrating-redux-with-a-ui

// 1) Create a new Redux store
const store = configureStore({reducer: counterReducer})

// 2) Subscribe to redraw whenever the data changes in the future
store.subscribe(render)

// Our "user interface" is some text in a single HTML element
const valueEl = document.getElementById('value')

// 3) When the subscription callback runs:
function render() {
  // 3.1) Get the current store state
  const state = store.getState()
  // 3.2) Extract the data you want
  const newValue = state.value.toString()

  // 3.3) Update the UI with the new value
  valueEl.innerHTML = newValue
}

// 4) Display the UI with the initial store state
render()

与 Redux 集成的每个 UI 层都需要执行相同的基本操作:订阅、获取最新状态、此组件所需的差异值、如果这些值发生变化则强制重新绘制以及必要的更新。

对于 React,我们将所有逻辑封装在 React-Redux 包和我们的

useSelector
钩子(以及旧的
connect
包装器)中。 RTK Query 的 React hooks 像
useGetPokemonQuery
建立在它之上。

对于 Stencil,您需要从使用任何与 React-Redux 等效的东西开始。我看到在 https://stenciljs.com/docs/stencil-redux 已经有一个讨论使用 Redux 的 Stencil 文档页面,并且有一个

@stencil/redux
包。

与 Redux 和 RTK 的其余部分一样,RTK 查询也是 UI 不可知的。所以,你可以在没有 React 的情况下使用它,但是你必须做更多的工作。

我们在文档中介绍了一些关键部分:

在这种情况下,您可能希望根据

const selector = api.endpoints.getPokemon.select("pikachu")
生成端点选择器,并将其传递给 Stencil 包装器
mapStateToProps
以从存储中选择该数据。假设
@stencil/redux
做我认为它做的事,那 should 触发组件中的更新。

© www.soinside.com 2019 - 2024. All rights reserved.