Предотвратите повторную выборку данных React в родительском компоненте

#reactjs #typescript #react-hooks #fetch

Вопрос:

В моем родительском компоненте, Dashboard.tsx, у меня есть дочерний компонент, Expenses.tsx, который выполняет вызов выборки API, а затем отображает данные. Родительский компонент имеет маршрутизатор, который позволяет вам переходить по разным URL-адресам в родительском компоненте, что заставляет все перерисовываться каждый раз, когда вы переходите по новому пути или отображаете новый дочерний компонент. Как я могу сделать так, чтобы этот вызов выборки выполнялся только один раз? Я пробовал использовать крючок useRef (), но он повторно инициализируется каждый раз при повторном рендеринге, и у меня та же проблема.

Вот панель мониторинга.tsx:

 export const Dashboard = () => {
  const d = new Date()
  const history = useHistory()
  const { user, setUser } = useAuth()
  const [categories, setCategories] = useState({
    expenseCategories: [],
    incomeCategories: []
  })
  
  const getCategories = async(user_id: number) => {
    await fetch(`/api/getCategories?user_id=${user_id}`)
    .then(result => result.json())
    .then(result => setCategories(result))
  }

  useEffect(() => {
    if (user.info.user_id) {
      getCategories(user.info.user_id)
    }
  }, [])

  const dashboardItems = [
    {
      value: 'Add Expense',
      path: '/dashboard/addExpense'
    },
    {
      value: 'Add Income',
      path: '/dashboard/addIncome'
    },
    { 
      value: 'Logout',
      path: '/login',
      onClick : async() => {
        localStorage.clear()
        setUser({
          info: {
            user_id: null,
            email: null,
            username: null
          },
          token: null
        })
      },
      float: 'ml-auto'
    }
  ]

  return(
    <div>
      <DashboardNavbar items={dashboardItems}/>
      <div className="wrapper">
      <p>{`Hello, ${user.info.username}!`}</p>
      <DateAndTime />
      <Expenses date={d}/>
      <Income date={d}/>
      <Switch>
        <Route path='/dashboard/addExpense'>
          <AddItemForm user={user} type={'expenses'} categories={categories.expenseCategories} />
        </Route>
        <Route path='/dashboard/addIncome'>
          <AddItemForm user={user} type={'income'} categories={categories.incomeCategories} />
        </Route>
      </Switch>
      <Logout />
      </div>
    </div>
  )
}
 

А вот файл Expenses.tsx, где выполняется вызов выборки:

 export const Expenses = (props: ExpensesProps) => {

  const [isLoading, setIsLoading] = useState(true)

  const { date } = props

  const { user } = useAuth()
  
  const m = date.getMonth()   1
  const s = '0'.concat(m.toString())

  const [total, setTotal] = useState<number>(0)
  
  useEffect(() => {
    const getTotalExpenses = async() => {
      await fetch(`/api/expenses?user_id=${user.info.user_id}amp;month=${s}`)
      .then(response => response.json())
      .then(result => {
        if (result) {
          setTotal(parseFloat(result))
        } 
      })
      .then(result => {
        setIsLoading(false)
      })
    }

    if (user.info.user_id) {
      getTotalExpenses()
    }
  }, [])  

  return isLoading ? (
    <div>
      loading...
    </div>
  ) : (
    <div>
      {`Your monthly expenses so far are: ${total}.`}
    </div>
  )
}
 

Комментарии:

1. Каждый экземпляр Expenses отличается, поэтому, если вы хотите, чтобы новый экземпляр получал доступ к данным из предыдущего экземпляра, вам нужно хранить эти данные выше в цепочке. Вы можете хранить его Dashboard и передавать реквизит, например total , setTotal и. Или вы могли бы использовать что-то вроде Redux, которое использует контексты реакции.

2. Ах, в этом есть смысл. Хорошо — если я все же сохраню его Dashboard , не будет ли он перерисовываться каждый раз Dashboard при повторных отправках, всякий раз, когда я перехожу на новый маршрут? Тогда он в конечном итоге будет демонстрировать то же поведение (повторная выборка).

3. Вам нужно будет добавить какую-то условную проверку, чтобы вы могли получать данные только в том случае, если у вас еще нет данных.

4. правильно — чего я не понимаю, так это как или где хранить эти данные после первоначальной выборки, чтобы я не извлекал их снова. У меня возникли проблемы с тем, чтобы заставить пользователя сделать это — как бы вы порекомендовали ?