У useEffect отсутствует зависимость - PullRequest
0 голосов
/ 25 марта 2020

Насколько я могу судить, я не могу удалить предупреждение ESlinting о том, что у моего useEffect отсутствует зависимость fetchProfile (). Когда я добавляю fetchProfile в массив зависимостей, я получаю бесконечный l oop. Буду очень признателен за любые предложения, которые могут помочь мне подавить это предупреждение. Код выглядит следующим образом:

import React, { useEffect, useContext, useReducer } from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import './App.css'
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles/'
import UserContext from './contexts/UserContext'
import jwtDecode from 'jwt-decode'
import axios from 'axios'

// utils
import reducer from './utils/reducer'
import themeFile from './utils/theme'
import AuthRoute from './utils/AuthRoute'
import UnAuthRoute from './utils/UnAuthRoute'

// Components
import NavBar from './components/NavBar'

// Pages
import Home from './pages/Home'
import Login from './pages/Login'
import Profile from './pages/Profile'
import SignUp from './pages/SignUp'
import Admin from './pages/Admin'
import Dashboard from './pages/Dashboard'
import Alumni from './pages/Alumni'

// context
import { ProfileContext } from './contexts/ProfileContext'

const theme = createMuiTheme(themeFile)

// axios.defaults.baseURL = `https://us-central1-jobtracker-4f14f.cloudfunctions.net/api`

const App = () => {
  const initialState = useContext(UserContext)
  const [user, setUser] = useContext(ProfileContext)
  const [state, dispatch] = useReducer(reducer, initialState)

  const fetchProfile = async token => {
    await axios
      .get(`/user`, {
        headers: {
          Authorization: `${token}`
        }
      })
      .then(res => {
        setUser(res.data)
      })
      .catch(err => console.log({ err }))
  }
  // keeps userContext authorized if signed in
  useEffect(
    _ => {
      const token = localStorage.FBIdToken
      if (token && token !== 'Bearer undefined') {
        const decodedToken = jwtDecode(token)
        if (decodedToken.exp * 1000 < Date.now()) {
          localStorage.removeItem('FBIdToken')
          dispatch({ type: 'LOGOUT' })
        } else {
          dispatch({ type: 'LOGIN' })
          state.isAuth && fetchProfile(token)
        }
      } else {
        dispatch({ type: 'LOGOUT' })
        localStorage.removeItem('FBIdToken')
      }
    },
    [state.isAuth]
  )

  return (
    <MuiThemeProvider theme={theme}>
      <UserContext.Provider value={{ state, dispatch }}>
        <div className="App">
          <Router>
            <NavBar isAuth={state.isAuth} />
            <div className="container">
              <Switch>
                <Route exact path="/" component={Home} />
                <UnAuthRoute
                  path="/signup"
                  component={SignUp}
                  isAuth={state.isAuth}
                />
                <UnAuthRoute
                  path="/login"
                  component={Login}
                  isAuth={state.isAuth}
                />
                <AuthRoute
                  path="/profile"
                  component={Profile}
                  isAuth={state.isAuth}
                />
                <AuthRoute
                  path="/dashboard"
                  component={Dashboard}
                  isAuth={state.isAuth}
                />
                <Route path="/admin" component={Admin} isAuth={state.isAuth} />
                <AuthRoute
                  path="/users/:id"
                  component={Alumni}
                  isAuth={state.isAuth}
                />
              </Switch>
            </div>
          </Router>
        </div>
      </UserContext.Provider>
    </MuiThemeProvider>
  )
}

export default App

1 Ответ

2 голосов
/ 25 марта 2020

Вы можете сделать одно из двух:

  1. Полностью убрать fetchProfile из компонента и использовать его результат вместо того, чтобы вызывать setUser напрямую.

  2. Memoize fetchProfile, поэтому вы создаете новый только тогда, когда что-то зависит от изменений (что ... никогда, потому что fetchProfile зависит только от setUser, который стабилен). (Вы могли бы сделать это с useMemo или его близким родственником useCallback, вероятно, хотя в теории useMemo [и это useCallback] предназначены для повышения производительности, не "семанти c гарантия.")

Для меня # 1 - ваш лучший выбор. За пределами вашего компонента:

const fetchProfile = token => {
  return axios
    .get(`/user`, {
      headers: {
        Authorization: `${token}`
      }
    })
}

затем

useEffect(
  _ => {
    const token = localStorage.FBIdToken
    if (token && token !== 'Bearer undefined') {
      const decodedToken = jwtDecode(token)
      if (decodedToken.exp * 1000 < Date.now()) {
        localStorage.removeItem('FBIdToken')
        dispatch({ type: 'LOGOUT' })
      } else {
        dispatch({ type: 'LOGIN' })
        if (state.isAuth) {                         // ***
            fetchProfile(token)                     // ***
            .then(res => setUser(res.data))         // ***
            .catch(error => console.error(error))   // ***
        }                                           // ***
      }
    } else {
      dispatch({ type: 'LOGOUT' })
      localStorage.removeItem('FBIdToken')
    }
  },
  [state.isAuth]
)

Поскольку действие является асинхронным, вы можете отменить / проигнорировать его, если компонент повторно выполняет рендеринг в это время (это зависит от ваш вариант использования).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...