【问题标题】:how to asynchronously render a functional component in react?如何在反应中异步渲染功能组件?
【发布时间】:2022-01-05 02:47:23
【问题描述】:

基本上,我需要根据一个异步设置的状态来渲染一个组件,默认状态是“false”,所以组件会挂载并抛出对应于 false 选项的返回,但它不会等待更新状态的前提。

export const LayoutValidator=({children})=>{

  const [auth,setAuth] = useState(undefined)
  const {token} = JSON.parse(localStorage.getItem("loggedUser")||'{}');
  
  fetch(`${urlValue}/api/validate-token`,{
    method:"POST",
    headers:{
      authorization: token,
    }
  })
  .then(ans=>ans.json())
  .then(ans=>setAuth(ans.auth))
  .catch(err=>console.log(err))

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

如何设置此组件在返回其答案之前等待前提?

【问题讨论】:

  • 您需要第三种状态,“正在加载”。在您确认他们的令牌无效之前不要重定向用户。
  • 是的,先生!它是由这个组件实现的,这个应用程序的身份验证逻辑有一些我在这个问题中省略的复杂性。
  • 哦,还要确保将fetch() 放入useEffect 钩子中,这样它就不会在每次渲染时一次又一次地运行。
  • 你说的“太晚了”是什么意思?无论如何,在第一次渲染之后状态会更新(setAuth(ans.auth)),因为 http 请求是异步的并且需要一些时间。这就是为什么你需要进入“加载”状态。
  • 例如,通过区分undefinedtruefalse 之间的auth,或任何其他三元逻辑。在加载状态下不渲染 (null) 或加载指示器。 (实际上你可能想要第四个错误状态,在组件中呈现消息而不是登录到控制台并保持显示在加载中)

标签: javascript reactjs asynchronous react-functional-component


【解决方案1】:

您可以创建自定义“获取挂钩”,然后您可以在其中获取数据并设置加载状态:

const { useEffect, useState } = React

const useFetchUsers = () => {
  const [users, setUsers] = useState([])
  const [loading, setLoading] = useState(false)
  
  useEffect(() => {
    setLoading(() => true)
    // setTimeout added to emphasize async nature
    setTimeout(() => {
      fetch('https://jsonplaceholder.typicode.com/users/')
        .then(response => response.json())
        .then(json => setUsers(() => json))
        .finally(setLoading(() => false))
    }, 1000)
    
  }, [])
  
  return {
    users,
    loading,
  }
}

const UserItem = ({ id, name, username, email }) => {
  return (
    <div>
      {name} - {username} - {email}
    </div>
  )
}

const App = () => {
  const { users, loading } = useFetchUsers()
  
  return (
    <div>
      {
        !loading
        ? users.map((user) => {
          return (
            <UserItem
              key={user.id}
              {...user}
            />
          )
        })
        : "Loading users..."
      }
    </div>
  )
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<div id="root"></div>

【讨论】:

  • 非常感谢先生的帮助,您给了我正确的方向。
【解决方案2】:

好的,这并不像我想象的那么简单(至少对我而言),非常感谢 @Bergi 和 @muka.gergely 以及帮助我​​获得最终解决方案的资源作者:https://www.debuggr.io/react-update-unmounted-component/

这是我带来的:

export const LayoutValidator=({children})=>{
  const {invalid, auth} = useFetchToken()
  return !invalid ? <Intermediate children={children}/> : <Navigate to="/" />
}

function Intermediate ({children}) {
  const {invalid, auth} = useFetchToken()
  return !auth ? <SplashScreen/> : children
}

function useFetchToken() {

  const { token } = JSON.parse(localStorage.getItem("loggedUser") || '{}')
  const [invalid, setInvalid] = useState(false)
  const [auth, setAuth] = useState(false)

  useEffect(()=>{
    let mounted = true
    setInvalid(() => true)
    fetch(`${urlValue}/api/validate-token`, {
    method: "POST",
    headers: {
      authorization: token,
    }
  })
    .then(ans => ans.json())
    .then(ans => mounted && setAuth(()=>ans.auth))
    .catch(err => console.log(err))
    .finally(setInvalid(()=>false))

    return () => mounted = false;
  },[])
  return {invalid, auth}
}

在我的情况下,它工作得很好,希望这对将来的人有所帮助。

【讨论】:

    猜你喜欢
    • 2019-05-18
    • 1970-01-01
    • 2021-10-23
    • 2020-12-07
    • 2020-06-30
    • 1970-01-01
    • 2020-03-18
    • 2017-09-19
    相关资源
    最近更新 更多