我正在尝试使用Slider/Select来获取用户查询参数,这将对URL进行进一步更改(通过handleChange),并通过fetch钩子进行api调用。
但是,当我将"滑块"值从1更改为0.1时,不会发生任何事情,但如果我将滑块值再次更改为0.1到0.2,它将返回0.1的结果(因此滞后1次单击)。使用"选择"值可以观察到类似的行为。
网址:https://thisorthatstockfrontend.herokuapp.com/rankStockSharpeFiltered
我没有表单控制,但在尝试了表单控制后,似乎并没有解决问题。我真的不想有一个提交按钮,任何帮助都很感激!
import React from 'react'
import { NavLink } from 'react-router-dom'
import { Button,InputLabel } from '@mui/material'
import { Typography,MenuItem } from '@mui/material'
import { DataGrid } from '@mui/x-data-grid'
import Slider from '@mui/material/Slider';
import { useEffect } from 'react'
import {FormControl} from '@mui/material';
import { useState } from 'react'
import { useFetch } from '../hooks/useFetch';
import { useForm,Controller } from "react-hook-form";
import Select,{SelectChangeEvent} from '@mui/material/Select';
import Grid from '@mui/material/Grid'
import { Box } from '@mui/system';
export default function StockListedFiltered()
{
const [values, setValues] = useState(
{
sharpeYear1: 1,
sharpeYear2: 5,
sharperatio1Cutoff: 1,
sharperatio2Cutoff: 1,
}
);
const [url,seturl]=useState('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
const handleChange = (propertyName) => (event) => {
console.log('hello')
event.preventDefault();
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values)
seturl('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
console.log(url)
};
const{data:stockPerformance ,isPending,error}=useFetch(url)
const columns=[
{field:'stockName', headerName:'ticker',width:200 },
{field:'years', headerName:'years' ,width:200},
{field:'SharpeRatio', headerName:'sharpe ratio',width:200},
{field:'AnnualReturn', headerName:'annual return',width:200 },
{field:'AnnualVolatility', headerName:'annual volatility',width:200 }
];
return (
<div>
<h2 style={{paddingTop:'3rem',textAlign:'center',paddingBottom:'2rem'}}> Filtered Stocks Ranked </h2>
<NavLink to="/rankStockSharpe">
<Button>
<Typography>All stock </Typography>
</Button>
</NavLink>
<NavLink to="/rankStockSharpeFiltered">
<Button>
<Typography>Filtered </Typography>
</Button>
</NavLink>
<Grid container style={{paddingTop:'2rem',textAlign:'center'}}>
<Grid item xs={2}></Grid>
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<Select
defaultValue={1}
labelId="sharpeYear1"
id="sharpeYear1-select"
value={values.sharpeYear1}
label="Year"
onChange={handleChange("sharpeYear1")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio1Cutoff}
onChange={ handleChange("sharperatio1Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid >
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<Select
defaultValue={5}
labelId="sharpeYear2"
id="sharpeYear2-select"
value={values.sharpeYear2}
label="Year"
onChange={handleChange("sharpeYear2")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio2Cutoff}
onChange={handleChange("sharperatio2Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid>
</Grid>
<div style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
{isPending&&<div>Loading Data...</div>}
{error &&<div>"This is awkard..."{error}</div>}
{!isPending && stockPerformance&&
<div style={{height:500,width:'70%'}}>
<DataGrid
rows={stockPerformance}
columns={columns}
></DataGrid>
</div>
}
</div>
</div>
)
}
useState
是异步的,因此更新状态&那么在下一行中立即访问它将不起作用。更新状态仅在下一个渲染循环中可用。
以下内容不会对更新后的状态进行控制台日志记录。与setUrl
相同。
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values) // state is not yet updated
如果你想对状态更新执行操作,你需要使用useEffect
钩子,就像在类组件中使用componentDidUpdate一样,因为useState
返回的setter没有回调模式
useEffect(() => {
// action on update of values
console.log(values) // updated state is available here
}, [values]);
您可以克隆values
状态,通过更改和更新状态来进行更改。然后使用修改后的对象来计算url,使其具有新的值。
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
seturl(
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
newValues.sharpeYear1 +
'&LongYearNum=' +
newValues.sharpeYear2 +
'&sharpeRatio1=' +
newValues.sharperatio1Cutoff +
'&sharpeRatio2=' +
newValues.sharperatio2Cutoff
);
};
或者更好的是,第二次计算url(不直接在处理程序中),而且它不必处于状态。
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
};
const url = useMemo(() => {
return (
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
values.sharpeYear1 +
'&LongYearNum=' +
values.sharpeYear2 +
'&sharpeRatio1=' +
values.sharperatio1Cutoff +
'&sharpeRatio2=' +
values.sharperatio2Cutoff
);
}, [values]);
顺便说一句,在这个回调中,事件可以是null
,对其进行解构,以便将其分配给变量或使用event.persist()
。
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));