我在构建React单页应用程序以及如何解决它们时遇到的一些问题
#javascript #react #reactrouter #debounce

进入路线更改的页面顶部

默认情况下,React路由器不会在更改路线后将您带到新组件的顶部,而是像导航到新页面之前的页面位置一样。为了解决此问题,我们将在src文件夹中的辅助文件夹helpers中创建ScrollToTop JavaScript文件,并在下面添加代码。

import { useEffect } from "react"
import { useLocation } from "react-router-dom"

const ScrollToTop = () => {
  const { pathname } = useLocation()

  useEffect(() => {
    window.scrollTo(0, 0)
  }, [pathname])

  return null
}

export default ScrollToTop

我们从useLocation()钩上破坏了当前位置的pathname,并在组件中添加了一个useEffect()钩。 useEffect()钩具有pathname作为其依赖性。在每个页面上,该页面都将被迫滚动到顶部。

此指令将在App组件中使用:

import React from "react"
import { BrowserRouter } from "react-router-dom"
import ScrollToTop from "./helpers/ScrollToTop";

function App() {
  return (
    <BrowserRouter>
      <ScrollToTop />
      <App />
    </BrowserRouter>
  );
}

使用谴责

辩论是一种编程模式,其中执行执行昂贵或耗时的操作的某个功能通常会延迟特定时间(通常在几秒钟内)来提高应用程序的性能。

需要一个延迟参数,该参数确定在执行任务之前将等待多长时间。这样的任务可以包括在列表中搜索或最重要的是执行异步请求。

通常用于限制用户仍在输入时对API的不必要调用的数量。

与VUE不同,在React中使用的调试并不是那么简单。那里有很多解决方案,其中一些使用useMemouseCallback的挂钩。

这就是我能够解决这个问题的方式:

让我们在helpers文件夹中创建一个useDebounce文件。

import { useState, useEffect } from "react"

const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState(value)

  useEffect(
    () => {
      const handler = setTimeout(() => {
        setDebouncedValue(value)
     }, delay)
      return () => {
        clearTimeout(handler)
      }
    },
    [value, delay]
  )
  return debouncedValue
}

export default useDebounce
  • 我们创建了一个useDebounce函数,该函数采用两个参数,value a delay。这是我们要扣除的价值,以及我们要在更改此值以毫秒之前要延迟多长时间。

  • 然后将value存储在useState钩中。

  • useEffect挂钩接收一个setTimeout函数,该函数在更改value之前根据delay参数的值延迟。

  • delayvalue参数也是useEffect依赖项。

  • 之后,setTimeout被清除或中止,useEffect也已退出。

  • 只有在一个或两个依赖性变化时,useEffect钩才能再次运行。

以下是useDebounce函数的用例。

import React, { useEffect, useState  } from "react"
import useDebounce from "./utils/useDebounce"

const Universities = () => {
  const [data, setData] = useState([])
  const [term, setTerm] = useState("")
  const debouncedTerm = useDebounce(term, 500)

  const search = name => {
    fetch(`http://universities.hipolabs.com/search?name=${name}`)
      .then(res => res.json())
      .then(data => {
        setData(data)
        console.log(data)
      })
  }
  const clear = () => {
    setData([])
    setTerm("")
  }
  useEffect(() => {
    search(debouncedTerm)
  }, [debouncedTerm])

  return (
    <div>
      <div className="relative w-[98%] mx-auto">
        <input
          type="text"
          autoComplete="off"
          onChange={e => setTerm(e.target.value)}
          value={term}
          placeholder="Search movies"
          style={{
            backgroundColor: " rgb(229 231 235)",
            color: "rgb(17 24 39)",
            width: "100%",
            padding: "1rem",
          }}
        />
        <button onClick={() => clear()}>
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            strokeWidth={1.5}
            stroke="currentColor"
            style={{ cursor: "pointer", width: "5rem", height: "5rem" }}
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M6 18L18 6M6 6l12 12"
            />
          </svg>
        </button>
      </div>
      {data.map((item, index) => (
        <div key={index}>{item.name}</div>
      ))}
     Demonstrating debounce with asynchronous call for a university api.
    </div>
  )
}

我们使用较早创建的useDebounce函数拒绝了term状态,并在search函数和TH useEffect阵列依赖项中使用了debouncedTerm

保护路线

与VUE不同,React不提供针对没有某些身份验证和授权的用户的路线的开箱即用解决方案。

为了证明这一点,我将使用上下文API创建一个auth状态和一个toggleAuth函数,该函数模仿了可以在应用程序中任何地方使用的用户的登录和注销。

//AuthContext.js
import React, { createContext, useState } from "react"

export const AuthContext = createContext()

const AuthContextProvider = ({ children }) => {
  const [auth, setAuth] = useState(false)

  const toggleAuth = () => setAuth(!auth)

  return (
    <AuthContext.Provider value={{ auth, toggleAuth }}>
      {children}
    </AuthContext.Provider>
  )
}

export default AuthContextProvider

我们现在必须创建一个ProtectedRoutes文件。在此文件中,我们提取auth状态,并根据auth的值确定是否显示路线或导航用户到登录页面,也就是说,如果是truefalse

<Outlet> 应在父路由元素中使用以呈现其子路由元素。这允许嵌套UI在渲染子路线时出现。如果父路线完全匹配,则它将渲染子索引路由或没有索引路线。

是一种特殊组件,用于渲染父途径的子组件。它充当允许子组件在父组件中渲染的占位符。

不要忘记用AuthContextProvider包装您的应用程序。

import React from "react"
import { Navigate, Outlet } from "react-router-dom"
import { AuthContext } from "../context/AuthContext"

const ProtectedRoutes = () => {
  const { auth } = useContext(AuthContext)

  return auth ? <Outlet /> : <Navigate to="/login" />
}

export default ProtectedRoutes

我们现在可以在路线定义中使用受保护的路线。

<Route element={<ProtectedRoutes />}>
  <Route element={<Home />} path="/" exact />
  <Route element={<Products />} path="/products" />
</Route>

我们提供了ProtectedRoutes文件作为路由组件的元素组件支柱,它将包裹我们要保护的组件。

结论

总而言之,构建React单页应用程序可以带来自己的一系列挑战。其中一些挑战可能包括保护路线,使用审问以及在路线更改时进入页面顶部。但是,有几种解决这些问题的解决方案。

可以使用身份验证和授权技术来解决保护路线。这样可以确保只有身份验证的用户才能访问应用程序的某些部分。辩论的使用有助于通过减少函数调用的数量来防止性能问题和超负荷。可以使用scrollto窗口方法来实现路由更改的页面顶部。

通过应用这些解决方案,开发人员可以改善其React Spa的功能和用户体验。