如何在不重新渲染的情况下在基本应用程序组件中使用 GraphQL 挂钩进行反应?

How to use a GraphQL hook in a base app component in react without re-rendering?

我正在尝试在 React 上将 redux 与 GraphQL const sliceQuery = useQuery(ALL_SLICES) 结合使用,但由于 GraphQL 钩子及其承诺 Object { data: {}, variables: {}, refetch: (), fetchMore: (), updateQuery: (), startPolling: (), stopPolling: (), subscribeToMore: (), loading: true, networkStatus: 1, … },我似乎无法使用 useEffect 来最小化渲染。因此,我不得不在 useEffect 之外更新 props.slices,因为我必须等待 GraphQL 挂钩完成以下加载:

if (!sliceQuery.loading && props.slices === null) {
  const allSlices = sliceQuery.data.allSlices
  props.initializeSlices(allSlices)
  props.setCurrentSlice(allSlices.find(s => s._id === splitUrl[5]))
}

这是我的完整 App.js 组件:

import React, { useEffect } from 'react'
import { initializeSlices } from './reducers/sliceReducer'
import { setCurrentSlice } from './reducers/currentSliceReducer'
import { connect } from 'react-redux'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import { useQuery } from '@apollo/react-hooks'
import NavBar from './components/navBar/NavBar'
import Slice from './components/pages/Slice'
import About from './components/pages/About'
import Policies from './components/pages/Policies'
import Contact from './components/pages/Contact'
import './static/css/base.css'
import { ALL_SLICES } from './schemas'

const App = (props) => {
  console.log('App.js is ran')
  const sliceQuery = useQuery(ALL_SLICES)
  const splitUrl = window.location.href.split('/')
  if (!sliceQuery.loading && props.slices === null) {
    const allSlices = sliceQuery.data.allSlices
    props.initializeSlices(allSlices)
    props.setCurrentSlice(allSlices.find(s => s._id === splitUrl[5]))
  }

  const getSliceById = (id) => {
    return props.slices.find(s => s._id === id)
  }

  if (!props.slices || !props.currentSlice) {
    return (
      <div>
        <h1>loading..</h1>
      </div>
    )
  }
  return (
    <div className="wrapper">
      <Router>
        <NavBar />
        <Route exact path="/" render={() => <Slice slice={getSliceById('5e2db26efa3d070ec879b0e9')} /> } />
        <Route path="/slice/:name/:id" render={({match}) => <Slice slice={getSliceById(match.params.id)} /> } />
        <Route path="/about" render={() => <About /> } />
        <Route path="/policies" render={() => <Policies /> } />
        <Route path="/contact" render={() => <Contact /> } />
      </Router>
    </div>
  );
}
const mapStateToProps = (state) => {
  return {
    slices: state.slices,
    currentSlice: state.currentSlice,
  }
}

export default connect(
  mapStateToProps,
  { initializeSlices, setCurrentSlice }
)(App)

这是页面加载的控制台日志:

The development server has disconnected. Refresh the page if necessary.

[HMR] Waiting for update signal from WDS...

App.js is ran

./src/App.js Line 1:17: 'useEffect' is defined but never used no-unused-va

Warning: Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate. Check the render method of App.

App.js is ran

App.js is ran

App.js is ran

您仍然可以使用 useEffect 仅在您的数据可用时才执行您的方法。

const allSlices = 
    !sliceQuery.loading && props.slices === null 
        ? sliceQuery.data.allSlices 
        : null;

useEffect(() => {
    if(allSlices !== null) {
        props.initializeSlices(allSlices)
        props.setCurrentSlice(allSlices.find(s => s._id === splitUrl[5]))
    }
}, [allSlices, props.initializeSlices, props.setCurrentSlice])

这只会在 allSlices 可用时调用方法 props.initializeSlicesprops.setCurrentSlice

如果这些方法也在渲染时创建,您可能需要在创建它们的地方使用 useCallback 来阻止它们触发 useEffect 挂钩以在后续渲染上执行。