我正在尝试为我的数据添加排序功能,但我遇到了一些问题,我决定尝试使用 React 钩子,不确定我是否做错了什么,问题是当我通过 Select 选择某个值时,eventho 状态已更改,页面上没有差异, 在我第二次单击另一个值后(如果我单击相同的元素,则没有任何变化),然后一切开始正常工作,每次单击某个值时,都会应用不同的排序方式。为什么它从一开始就不想正常工作?
编辑: 首先在父组件中,我获取数据,然后通过 props:
父母:
const [data, setData] = useState("")
useEffect(() => getDeviceDataTotal(), [])
const getDeviceDataTotal = () => {
console.log('refresh clicked')
fetch("http://localhost:4000/device")
.then(res => res.json())
.then((res) => setData(res))
.catch(err => {
throw err;
});
};
<Route
exact
path="/"
render={() => <Dashboard classes={classes} data={data} refresh={getDeviceDataTotal}/> }
/>
子组件:
function Dashboard(props) {
const [selectedSort, setSelectedSort] = useState("1")
const [devices, setDevices] = useState(props.data)
useEffect(() => {
props.refresh();
setDevices(props.data)
},[devices])
useEffect(() => sortDeviceData(), [selectedSort])
const sortDeviceData = () => {
console.log(devices)
switch(selectedSort) {
case "device":
console.log(devices)
props.data.sort(function(a,b) {
return (a.device_id.toUpperCase() < b.device_id.toUpperCase()) ? -1 : (a.device_id.toUpperCase() > b.device_id.toUpperCase()) ? 1 : 0
})
setDevices(props.data)
break;
case "customer":
props.data.sort(function(a,b) {
return (a.customer.toUpperCase() < b.customer.toUpperCase()) ? -1 : (a.customer.toUpperCase() > b.customer.toUpperCase()) ? 1 : 0
})
setDevices(props.data)
break;
case "server":
props.data.sort(function(a,b) {
return (a.server.toUpperCase() < b.server.toUpperCase()) ? -1 : (a.server.toUpperCase() > b.server.toUpperCase()) ? 1 : 0
})
setDevices(props.data)
break;
case "creation":
props.data.sort(function(a,b) {
return (a.createdAt.toUpperCase() < b.createdAt.toUpperCase()) ? -1 : (a.createdAt.toUpperCase() > b.createdAt.toUpperCase()) ? 1 : 0
})
setDevices(props.data)
break;
case "update":
props.data.sort(function(a,b) {
return (a.updatedAt.toUpperCase() < b.updatedAt.toUpperCase()) ? -1 : (a.updatedAt.toUpperCase() > b.updatedAt.toUpperCase()) ? 1 : 0
})
setDevices(props.data)
break;
default:
return setDevices(props.data)
}
}
<div>
<FormControl className={classes.selectContainer}>
<Select
value={selectedSort}
style={{position: 'absolute', right: 0, bottom: 10, width: 150}}
onChange={e => setSelectedSort(e.target.value)}
>
<MenuItem value="1">Sort</MenuItem>
<MenuItem value="device">Device</MenuItem>
<MenuItem value="customer">User</MenuItem>
<MenuItem value="server">Server</MenuItem>
<MenuItem value="creation">Creation date</MenuItem>
<MenuItem value="update">Update date</MenuItem>
</Select>
</FormControl>
</div>
<div>
<DeviceList
classes={classes}
deviceData={devices ? devices: props.data}
filtered={props.filtered}
/>
</div>
你的刷新会异步更改 props,所以在使用Effect props.data ist 仍然为 null 或你给它的任何初始值。 然后,当设置 props.data 时(从刷新中解析的承诺),组件将重新渲染。但是由于设备没有变化,useEffect不会再次执行,并且设备永远不会设置为props.data中的新值。
我建议您决定父控件是否获取数据,然后您可以将设备传递到此组件中,或者此组件执行获取,然后您可以从 useEffect 中从此组件中刷新替换 setData 中的状态设置器中获取代码:
useEffect(() => {
fetch(....
.then(json => setDevices(json.devices)
}, [])
这将在首次渲染时运行一次,并且数据触发器的到达会与设备一起重新渲染。
为了避免 devices.sort 不是一个函数,添加一个守卫:如果(设备)...
只需将sortDeviceData设置为selectedSort的函数,并将selectedSort传入:
const sortDeviceData = selectedSort => {...}
由于 selectedSort 未在您的 useEffect 中使用,因此它不会被执行。
好吧,也许我不太确定发生了什么。我假设您最初从props.data获得设备?
然后,您可以通过在设备的useState中使用props.data 来省略第一个useEffect:
const [devices, setDevices] = useState(props.data)
然后,当您更改排序顺序时,您不应该就地更新 props.data - props 应该是只读的!
就个人而言,我会编写一个函数来返回给定 selectedSort 的比较器:
const comparator = selector => {
switch (selector) {
case „1“: return (a,b)=>...
...
}
}
然后做
useEffect(() => setDevices(devices.sort(comparator(selectedSort)))
, [selectedSort])
您正在获取子项中的数据,该数据在父项中设置状态。这是您作为数据传递给您的孩子。但是你调用 refreshin useEffect,它是异步的,所以你再次设置旧的 props.data。
删除您刷新的孩子中的 useEffect,并使用 props.data 作为您为设备使用 State 的初始属性。
可以删除仪表板的刷新属性。
您的父级控制着数据的获取,因此请依靠父级来做。