反应重定向未正确加载页面

时间:2020-07-20 14:14:44

标签: reactjs react-router react-router-dom

重定向反应时,页面url成功更改,但未加载任何内容。实际上,我收到一个TypeError: n is not a function错误。但是,如果我重新加载页面,则我重定向到该页面的加载就很好。我在这里想念什么?自从迁移到钩子以来,我一直在努力寻找一个直接的答案。我当前使用的唯一链接位于我的App.js中,并使用Material-UI按钮。

"react-router-dom": "^5.2.0"

App.js

...
<main className={classes.content}>
  <div className={classes.toolbar} />
  <BrowserRouter>
    <Switch>
      <Route exact path='/portal/:stateName/data/' component={DataView} />
      <Route exact path='/portal/data-comparison-tool' component={CompareTool} />
      <Route exact path='/portal/regional-analysis' component={RegionalAnalysis} />
      <Route exact path='/portal/reporting' component={Reporting} />
      <Route path='/portal/upload' component={UploadCsv} /> <--- Route in question
      <Route exact path='/portal/' component={Dashboard} />
    </Switch>
  </BrowserRouter>
</main>
...

Dashboard.js 这是我尝试在单击按钮时重定向的地方。选择按钮后,状态将更改,从而启用以下功能。

if (bulkUpload) {
  return (
    <Redirect to={{ pathname: '/portal/upload', state: { from: props.location } }} />
  )
}

UploadCsv 对方问,这是我要加载的组件。

...
export default function UploadCsv (props) {
  const classes = useStyles()
  const [doneLoading, setDoneLoading] = useState()
  const [uploadData, setUploadData] = useState([])
  const [dataSet, setDataSet] = useState(null)
  const [columns, setColumns] = useState(tableHfcCols)
  const [error, setError] = useState()
  const [dbData, setDbData] = useState()
  const [isProcessing, setIsProcessing] = useState()
  const [stateName, setStateName] = useState()
  const [existData, setExistData] = useState([])
  const [newData, setNewData] = useState([])
  const [openDialog, setOpenDialog] = useState()
  const [checks, setChecks] = useState({
    invalidCols: [],
    endUse: [],
    category: [],
    state: [],
    year: []
  })

  useEffect(async () => {
    async function load () {
      // load credential data
      const { data } = await axios('/account/fetch')
      await setStateName(data.user_state_name)
    }
    // Load
    await load()
    await setDoneLoading(true)
  }, [])

  const loadData = async () => {
    // Endpoints
    const scenarioEndpoint = `/api/measurements/${stateName}/`
    const metricsEndpoint = `/api/metrics/${stateName}/`

    // Gather measurements data for specific state
    if (dataSet === 'hfc') {
      const apiData = await axios(scenarioEndpoint).then(r => r.data.hfc_metrics)
      await setDbData(apiData)
      return apiData
    } else if (dataSet === 'state') {
      const apiData = await axios(metricsEndpoint).then(r => r.data.state_metrics)
      await setDbData(apiData)
      return apiData
    }
  }

  // add file to upload box
  const handleOnFileLoad = async (data) => {
    const headerClean = await CleanHeader(data)
    const dataSetName = await WhichData(headerClean)
    if (dataSetName === 'hfc') {
      const cleanData = await headerClean.map(d => ShapeHfcData(d))
      await setDataSet(dataSetName)
      await setColumns(tableHfcCols)
      await setUploadData(cleanData)
      // analyze data
      const { invalidCols } = await CheckColumns({ setName: 'hfc', data: cleanData })
      await setChecks({ ...checks, invalidCols: invalidCols })
      // clean end_use fields
    } else if (dataSetName === 'state') {
      const cleanData = await headerClean.map(d => ShapeStateData(d))
      await setDataSet(dataSetName)
      await setColumns(tableStateCols)
      await setUploadData(headerClean)
      // analyze data
      const { invalidCols } = await CheckColumns({ setName: 'state', data: cleanData })
      await setChecks({ ...checks, invalidCols: invalidCols })
    }
  }

  // Remove file from upload field
  const handleOnRemoveFile = async (data) => {
    setUploadData([])
    setColumns([])
    setDataSet()
  }

  const handlePrepSubmit = async () => {
    setIsProcessing(true)
    // get data
    const apiData = await loadData()
    // check which records exist and which don't
    const { exist, notExist } = await parseData({ apiData: apiData, uploadData: uploadData })
    // run checks and return results
    const { endUseCheck, categoryCheck, yearCheck, stateCheck } = await runChecks(uploadData)

    // update state
    await setChecks({
      ...checks,
      endUse: endUseCheck,
      category: categoryCheck,
      state: stateCheck,
      year: yearCheck
    })
    await setExistData(exist)
    await setNewData(notExist)
    await setOpenDialog(true)
  }

  const runChecks = async (data) => {
    // check if endUse values are correct
    const endUseCheck = []
    const categoryCheck = []
    const yearCheck = []
    const stateCheck = []
    data.forEach(async function (row) {
      const endUseStatus = await CheckEndUse(row.end_use)
      const categoryStatus = await CheckCategory(row.category)
      const stateStatus = await CheckState(row.state)
      const yearStatus = await CheckYear(row.year)
      if (endUseStatus === 'fail') {
        endUseCheck.push(row)
      } else if (categoryStatus === 'fail') {
        categoryCheck.push(row)
      } else if (stateStatus === 'fail') {
        stateCheck.push(row)
      } else if (yearStatus === 'fail') {
        yearCheck.push(row)
      }
    })
    return { endUseCheck, categoryCheck, yearCheck, stateCheck }
  }

  // Check to see which are updates and which are new records
  const parseData = ({ apiData, uploadData }) => {
    const exist = []
    const notExist = []

    const hfcHeader = [[...HfcHeader, ['id']].flat()][0]

    uploadData.forEach(function (row) {
      const dbRecordsYear = reducedFilter(apiData, hfcHeader, item => item.year === row.year)
      const dbRecordsCategory = reducedFilter(dbRecordsYear, hfcHeader, item => item.category === row.category)
      const record = reducedFilter(dbRecordsCategory, hfcHeader, item => item.end_use === row.end_use)
      const apiRecord = reducedFilterId(dbRecordsCategory, hfcHeader, item => item.end_use === row.end_use)

      if (record.length > 0) {
        row.id = apiRecord[0].id
        exist.push(row)
      } else if (record.length < 1) {
        notExist.push(row)
      }
    })

    return { exist, notExist }
  }

  // Dialog Actions
  const handleDialogClose = () => {
    setOpenDialog(false)
  }

  if (!doneLoading) {
    return <CircularProgress color='secondary' size='2.5rem' thickness='2.0' />
  }

  const submitData = async () => {
    const location = dataSet === 'hfc' ? 'measurements' : 'metrics'
    if (existData.length > 0) {
      existData.forEach(function (row) {
        updateRecord(row, location)
        console.log('update', row)
      })
    }

    if (newData.length > 0) {
      newData.forEach(function (row) {
        createRecord(row, location)
        console.log('create', row)
      })
    }
  }

  const updateRecord = async (row, location) => {
    // If the object exists, update it via API
    const endpoint = `/api/${location}/record/${row.id}/`
    await axios.put(endpoint, row)
  }

  const createRecord = async (row, location) => {
    const endpoint = `/api/${location}/create`
    await axios.post(endpoint, row)
  }

  console.log(uploadData)

  return (
    <>
      <Grid container className={classes.container}>
        <Toolbar className={classes.pageHeader}>
          <Typography className={classes.title} variant='h3' color='secondary' align='left'>
            Upload Data
          </Typography>
        </Toolbar>
        <Grid item xs={12}>
          <Paper className={classes.stagePaper}>
            <ReactMarkdown
              source={HelpText}
              escapeHtml={false}
            />
          </Paper>
        </Grid>
        <Grid item xs={6}>
          <Paper className={classes.middlePaper}>
            <Grid container className={classes.container}>
              <Toolbar className={classes.pageHeader}>
                <Typography className={classes.title} variant='h5' color='secondary' align='left'>
                Sample Data Sets
                </Typography>
              </Toolbar>
              <Grid item xs={12}>
                <SampleDataText />
              </Grid>
              <Grid item xs={6} className={classes.innerGrid}>
                <Button variant='outlined' fullWidth color='secondary' onClick={() => csvDownload(hfcData, 'scenario_sample_data.csv')}>Scenario Data</Button>
              </Grid>
              <Grid item xs={6} className={classes.innerGrid}>
                <Button variant='outlined' fullWidth color='primary' onClick={() => csvDownload(stateData, 'state_sample_data.csv')}>State Data</Button>
              </Grid>
            </Grid>
          </Paper>
        </Grid>
        <Grid item xs={6}>
          <Paper className={classes.middlePaper}>
            <Toolbar className={classes.pageHeader}>
              <Typography className={classes.title} variant='h5' color='secondary' align='left'>
                Upload .CSV File
              </Typography>
            </Toolbar>
            <Upload
              setError={setError}
              error={error}
              handleOnFileLoad={handleOnFileLoad}
              handleOnRemoveFile={handleOnRemoveFile}
            />
          </Paper>
        </Grid>
        {uploadData.length < 1
          ? ''
          : <Grid item xs={12} className={classes.stagePaper}>
            <MaterialButton
              onClick={() => handlePrepSubmit()}
              disabled={isProcessing}
              text={isProcessing ? 'PROCESSING PRELIM CHECKS...' : 'BEGIN UPLOAD'}
              color='accent'
              width='100'
            />
          </Grid>}
        <Grid item xs={12}>
          <Paper className={classes.stagePaper}>
            <link rel='stylesheet' href='https://fonts.googleapis.com/icon?family=Material+Icons' />
            <CustomMaterialTable
              title='Preview Data'
              columns={(uploadData.length > 0) ? columns : []}
              data={(uploadData.length > 0) ? uploadData : []}
              components={{
                Container: props => props.children
              }}
              options={{
                headerStyle: {
                  padding: '10px 4px 10px 4px',
                  fontSize: '.85rem'
                },
                cellStyle: {
                  padding: '14px 4px 14px 4px',
                  fontSize: '.8rem'
                },
                pageSize: uploadData.length,
                selection: true,
                rowStyle: rowData => ({ backgroundColor: rowData.tableData.checked ? '#37b15933' : '' })
              }}
              editable={{
                onRowAddCancelled: rowData => console.log('Row adding cancelled'),
                onRowUpdateCancelled: rowData => console.log('Row editing cancelled'),
                onRowAdd: newData =>
                  new Promise((resolve, reject) => {
                    setTimeout(() => {
                    /* setData([...data, newData]); */

                      resolve()
                    }, 1000)
                  }),
                onRowUpdate: (newData, oldData) =>
                  new Promise((resolve, reject) => {
                    setTimeout(() => {
                      const dataUpdate = [...uploadData]
                      const index = oldData.tableData.id
                      dataUpdate[index] = newData
                      setUploadData([...dataUpdate])

                      resolve()
                    }, 1000)
                  }),
                onRowDelete: oldData =>
                  new Promise((resolve, reject) => {
                    setTimeout(() => {
                      const dataDelete = [...uploadData]
                      const index = oldData.tableData.id
                      dataDelete.splice(index, 1)
                      setUploadData([...dataDelete])

                      resolve()
                    }, 1000)
                  })
              }}

            />
          </Paper>
        </Grid>
      </Grid>
      <Footer />
      <UploadPop
        openDialog={openDialog}
        handleDialogClose={handleDialogClose}
        existData={existData}
        newData={newData}
        submitData={submitData}
        checks={checks}
      />
    </>
  )
}

2 个答案:

答案 0 :(得分:0)

尝试将/portal/upload/的路由路径更改为

<Route exact path='/portal/upload' component={UploadCsv} />

如果这不能解决问题,则可能必须发布{UploadCsv}的定义

答案 1 :(得分:0)

我从来没有找到一个直接的答案。这显然是一个漂亮的common problem,据我所见,大多数人似乎都在解决它。我对React-Router感到头疼的部分原因是为什么我喜欢与Nextjs一起工作这么多。

这是我的解决方法,因为我无法使用React Router v5使history.push(/portal/)正常工作。

window.location.href = '/portal/'

这不是理想的解决方案,但是可以解决我90%的用例。该继续前进了。