redux Stencil.js & RTK查询:避免无限的回调

piah890a  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(141)

我正在尝试确定我是否使用RTKQuery来保持Stencil.js组件的状态与DB正确同步。
我的行为是,我的组件将使用RTK查询和store.dispatch()获取数据,并将其分配给本地状态,然后用户改变组件,这也是使用rtk查询API通过storedispatch()函数发出的请求。
我设法让组件重新呈现的唯一方法是使用componentWIllLoad()生命周期方法订阅存储并传入一个fetch函数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' }],
    }),

一个还原商店:

- 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()回调函数。
谢谢!

chhqkbe1

chhqkbe11#

这实际上分为3个问题:

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

对于前两个主题,请参阅我的博客文章The History and Implementation of React-Redux和talk A Deep Dive into 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 Package 器)中。RTK Query的React钩子(如useGetPokemonQuery)构建在其之上。
对于Stencil,你需要从使用React-Redux的等价物开始,我看到已经有一个Stencil文档页面在https://stenciljs.com/docs/stencil-redux上讨论使用Redux,并且有一个@stencil/redux包。
像Redux和RTK的其他部分一样,RTK Query也是UI不可知的。所以,你可以在没有React的情况下使用它,但是你必须做更多的工作。
我们在文档中介绍了一些关键信息:

在本例中,您可能希望生成一个沿着const selector = api.endpoints.getPokemon.select("pikachu")的端点选择器,并将其传递给Stencil Package 器mapStateToProps,以便从存储中选择该数据。假设@stencil/redux执行了我认为它执行的操作,则 * 应该 * 触发组件中的更新。

相关问题