重定向反应时,页面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}
/>
</>
)
}
答案 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%的用例。该继续前进了。