【问题标题】:How can I share state between two custom hooks?如何在两个自定义钩子之间共享状态?
【发布时间】:2019-09-19 16:54:29
【问题描述】:

我正在尝试从 Spotify API 获取数据。由于我需要一个访问令牌来执行此操作,因此我构建了一个自定义挂钩来解析来自服务器的 URL 中的令牌。
我还有另一个自定义钩子,其中包含对 API 的实际请求,它将解析的令牌作为参数。两者都聚集在一个父挂钩中。

我无法完成这项工作,因为令牌永远不会到达请求挂钩的范围,所以它失败了。如果我解析令牌并在同一个钩子中发出请求,一切都会很好。我打算为每个请求制作一个钩子,因为它不仅仅是一个,这就是为什么我想将令牌作为参数传递。

令牌自定义挂钩

export default () => {
  const [ token, setToken ] = useState('')
  useEffect(() => {
    const { access_token } = queryString.parse(window.location.search)
    return setToken(access_token)
  }, [])
  return token
}

请求钩子

export default function useFetchUserData(token) {
  //state
  const initialUserState = {
    display_name: '',
    external_url: '',
    images: ''
  }
  const [ userData, setUserData ] = useState(initialUserState)
  const [ isLoading, setIsLoading ] = useState(false)
  const [ isError, setIsError ] = useState(false)

  useEffect(() => {
    async function getUserData() {
      setIsLoading(true);
      setIsError(false);

      const spotify = axios.create({
        baseURL: 'https://api.spotify.com/v1/me',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      })
      try {
        const userRes = await spotify('/')
        .then( res => { return res.data });

        setUserData({
          display_name: userRes.display_name,
          external_url: userRes.external_urls.spotify,
          images: userRes.images[0].url
        })
      } catch (error) {
          setIsError(true)
      }
      setIsLoading(false);
    }
    getUserData();
  }, [])

  const data = {
    userData,
    isLoading,
    isError
  }
  return data
}

父挂钩

export default function Home() {

  const  token = useParseToken()
  const { userData, isLoading, isError } = useFetchUserData(token);

  if (isLoading) return <BarLoader />;
  if (isError) return <div>Oops! something went wrong</div>;

  return (
    <Fragment>
      <Header userData={userData}/>
    </Fragment>  
  )   
}

【问题讨论】:

  • 嗨@FedericoCastro,看看新的上下文API。听起来它非常适合您的用例!钩子的一部分是 useContext 钩子,它使上下文更易于使用!
  • 从您的示例代码中,const { token } = useTokenParser() 可能是错误的,应该是 const token = useTokenParser()
  • 那么在useFetchUserData内部你应该正确处理token === ""的情况,因为第一次调用总是得到那个情况。
  • 非常感谢@hackape,它成功了。我对解构感到非常兴奋。
  • 感谢@Jared,也许是时候试一试了!

标签: javascript reactjs axios react-hooks


【解决方案1】:

在您的情况下发生的情况是您在自定义挂钩中的 useEffect 挂钩中设置状态以设置令牌。但是,您无需等待效果运行就从该挂钩返回令牌,因此第一次调用 useFetchUserData 挂钩时,它将接收空字符串作为令牌。要解决这个问题,您必须实现 useFetchUserData 挂钩,以便在令牌可用或更改后运行

export default function useFetchUserData(token) {
  //state
  const initialUserState = {
    display_name: '',
    external_url: '',
    images: ''
  }
  const [ userData, setUserData ] = useState(initialUserState)
  const [ isLoading, setIsLoading ] = useState(false)
  const [ isError, setIsError ] = useState(false)

  useEffect(() => {
    async function getUserData() {
      setIsLoading(true);
      setIsError(false);

      const spotify = axios.create({
        baseURL: 'https://api.spotify.com/v1/me',
        headers: {
          'Authorization': `Bearer ${token}`
        }
      })
      try {
        const userRes = await spotify('/')
        .then( res => { return res.data });

        setUserData({
          display_name: userRes.display_name,
          external_url: userRes.external_urls.spotify,
          images: userRes.images[0].url
        })
      } catch (error) {
          setIsError(true)
      }
      setIsLoading(false);
    }
    if(token !== '' || token !== null) {
       getUserData();
    }
  }, [token])

  const data = {
    userData,
    isLoading,
    isError
  }
  return data
}

另外由于useParseToken返回了token,你在使用的时候不需要解构它

const token = useParseToken();

【讨论】:

    【解决方案2】:

    你必须使用 react 的 createContext api。 将您的令牌保存为上下文。并在任何你想要的地方使用它。 我认为this repository 会帮助你。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多