I am trying to use redux with GraphQL const sliceQuery = useQuery(ALL_SLICES)
on React but it seems as if i cant use useEffect to minimize renders due to GraphQL hooks and their promise Object { data: {}, variables: {}, refetch: (), fetchMore: (), updateQuery: (), startPolling: (), stopPolling: (), subscribeToMore: (), loading: true, networkStatus: 1, … }
. So instead i am forced to update props.slices
outside of a useEffect since i have to wait for the GraphQL hook to finish loading with the following:
if (!sliceQuery.loading && props.slices === null) {
const allSlices = sliceQuery.data.allSlices
props.initializeSlices(allSlices)
props.setCurrentSlice(allSlices.find(s => s._id === splitUrl[5]))
}
Here is my full App.js component:
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)
Here is the console log of just the page loading:
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
You can still use useEffect
to only execute your methods when your data becomes available.
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])
This will only call the methods props.initializeSlices
and props.setCurrentSlice
when allSlices
becomes available.
If these methods are also created at render time, you may need to use useCallback
where they are created to stop them triggering the useEffect
hook to execute on subsquent renders.