使用 useContext 时 props.history 未定义?

Posted

技术标签:

【中文标题】使用 useContext 时 props.history 未定义?【英文标题】:props.history is undefined when using useContext? 【发布时间】:2020-03-01 10:04:22 【问题描述】:

我已经设置了我的上下文,并且我有一个在表单提交后运行的函数handleSubmit。当我提交表单时,我希望结果显示在单独的页面dashboard 上。我正在使用 history.push()。

我的表单包含在withRouter HOC 中。

当我提交表单时,我收到“props.history is undefined

我还有另一个使用match.params 的函数,我也得到了未定义。所以我假设它与 React 路由器有关。

我认为我的 Context 文件可能是需要用 withRouter HOC 包装的文件,但该文件有两个导出。

我的上下文提供者

import React,  useState, useEffect, createContext  from 'react'

const AnimeContext = createContext()

const API = "https://api.jikan.moe/v3"


const AnimeProvider = (props) => 
  const urls = [
    `$API/top/anime/1/airing`,
    `$API/top/anime/1/tv`,
    `$API/top/anime/1/upcoming`,
  ]

  // State for Anime search form
  const [dataItems, setDataItems] = useState([])
  const [animeSearched, setAnimeSearched] = useState(false)

  // Fetch searched Anime
  async function handleSubmit(e) 
    e.preventDefault()

    const animeQuery = e.target.elements.anime.value
    const response = await fetch(`$API/search/anime?q=$animeQuery&page=1`)
    const animeData = await response.json()

    setDataItems(animeData.results)
    setAnimeSearched(!animeSearched)

    props.history.push('/dashboard')
  


  return (
    <AnimeContext.Provider value=
      topTv,
      setTopTv,
      topAiring,
      setTopAiring,
      topUpcoming,
      setTopUpcoming,
      dataItems,
      setDataItems,
      animeSearched,
      setAnimeSearched,
      fetching,
      anime,
      fetchTopAnime,
      fetchAnimeDetails,
      handleSubmit
    >
      props.children
    </AnimeContext.Provider>
  )


export  AnimeProvider, AnimeContext 

我的 SearchForm 组件

import React,  useContext  from 'react';
import  withRouter  from 'react-router-dom'
import styled from 'styled-components'
import AnimeCard from './AnimeCard/AnimeCard';
import  AnimeContext  from '../store/AnimeContext'


const SearchForm = () => 
  const  dataItems, animeSearched, handleSubmit  = useContext(AnimeContext)

  return (
    <div>
      <Form onSubmit=handleSubmit>
        <Input
          type="text"
          name="anime"
          placeholder="Enter title"
        />
        <FormButton type='submit'>Search</FormButton>
      </ Form>
      animeSearched
        ?
        <AnimeCard
          dataItems=dataItems
        />
        : null
    </div>
  )


export default withRouter(SearchForm)

【问题讨论】:

从哪里调用 AnimeProvider? @Dave.Q 看看我的回答 你可以用withRouter包裹AnimeProvider @PrakashKarena 我在我的 App.js 文件中调用它。它位于顶层,包裹着我的Router 【参考方案1】:

在 react-router 中,如果任何组件被渲染为子级或 Route 或来自从 Route 渲染的祖先并将路由器 props 传递给它,您将从 props 获得 history。但是它没有收到路由器props,我建议试试这个

你可以从react-router-dom使用Redirect

import  Redirect  from "react-router-dom";

const [redirect, setRedirect] = useState(false);

现在将redirect 的值设置为true,无论你想要什么

setRedirect(true);

就像你的情况

async function handleSubmit(e) 
    e.preventDefault()

    const animeQuery = e.target.elements.anime.value
    const response = await fetch(`$API/search/anime?q=$animeQuery&page=1`)
    const animeData = await response.json()

    setDataItems(animeData.results)
    setAnimeSearched(!animeSearched)

    setRedirect(true);
  

现在您可以将以下内容用于return 函数中的Redirection,就像这样

if(redirect) 
  return <Redirect to="/dashboard" />
  else 
  return (
     <Your-Component />
 )

【讨论】:

这对我也不起作用。它说“dataItems”是未定义的。这是我的仓库的link。【参考方案2】:

你总是可以在任何地方使用useHitory钩子!

import  useHistory  from 'react-router'
...
const Page = function(props) 
  let history = useHistory();
  ...
  history.push('/')
  ...

【讨论】:

这似乎对我不起作用。这是我收到的错误。 React Hook "useHistory" 在函数 "page" 中被调用,该函数既不是 React 函数组件也不是自定义 React Hook 函数 @Dave.Q 请尝试将“page”大写,抱歉这个愚蠢的错误! 我试过了,但我得到了TypeError: Cannot read property 'push' of undefined

以上是关于使用 useContext 时 props.history 未定义?的主要内容,如果未能解决你的问题,请参考以下文章

从 TypeScript 中的 useContext 解构值时出错

useContext 在 useQuery 时返回 null

useContext 和 Redux 有啥区别? [关闭]

如何有效减少使用useContext导致的不必要渲染

useContext 返回未定义

为啥 `useContext` 不重新渲染我的组件?