Если есть проблема с кодом реакции, где по какой-то причине все работает должным образом, когда я обновляю пользовательский интерфейс с MyApp.promise().then(<here>), но не в моем MyApp.promise().then().catch(<here>)
setData, который является моей возвращаемой функцией useState().then() работает нормально, а не в catch().catch(), отлично работает, поскольку catch() выполняется, как ожидалосьconsole.info() в свой компонент и вижу, что он больше не перерисовывается, когда обновления приходят с catch().Я предполагаю, что мой вопрос: что было бы особенного в функции catch(), чтобы реакция не велась бы?
Это код для моего приложения, обрабатывающего обновления статуса:
const useUpdateStatus = () => {
const [data,setData] = useState({status: STATUS.IDLE,changelog:null,tasks:[]})
const updateData = (d) => {
// We call setData with an anonymous function so we can merge previous
// data with new data
setData((prev) => {
console.info({ ...prev, ...d })
return { ...prev, ...d }
})
};
// Only once, we set the timer to periodically update status
useEffect(() => {
setInterval(() => {
MyApp.get('/system/upgrade')
.then((upgrade) => {
// If anything is not "pending", it means we are upgrading
for (var t of upgrade.tasks) {
if (t.status !== "pending") {
updateData({ status: STATUS.INSTALLING})
}
}
// updateData will call setData with the full status
// This works as intended, UI is updated on each step
updateData({ tasks: upgrade.tasks, changelog: upgrade.changelog})
})
.catch((e) => {
// If data can't be fetched, it probably means we are restarting
// services, so we updated the tasks array accordingly
setData((prev) => {
for (var t of prev.tasks) {
if (t['id'] === "restarting") {
t['status'] = 'running'
}
else if (t['status'] == "running") {
t['status'] = 'finished'
}
}
// The expected data is logged here
console.info(prev)
return prev
})
})
}, 1000);
},[])
return data
}
Это уровень представления:
// Using the hook :
const { changelog, tasks, status } = useUpdateStatus()
// Somewhere int he page :
<UpdateProgress tasks = {tasks}/>
// The actual components :
const UpdateProgress = (props) => {
return(
<div style = {{display: "flex", width: "100%"}}>
{ props.tasks.map(s => {
return(
<UpdateTask key = {s.name} task = {s}/>
)
})}
</div>
)
}
const UpdateTask = (props) => {
const colors = {
"pending":"LightGray",
"running":"SteelBlue",
"finished":"Green",
"failed":"red"
}
return(
<div style = {{ textAlign: "center", flex: "1" }}>
<Check fill = {colors[props.task.status]} width = "50px" height = "50px"/><br/>
<p style = {props.task.status== = "running" ? {fontWeight: 'bold'} : { fontWeight: 'normal'}}>{props.task.name}</p>
</div>
)
}





React выполняет сравнение Object.is, чтобы проверить, требуется ли повторный рендеринг после вызова обновления состояния. Поскольку вы изменяете состояние в блоке catch, response получает ложное уведомление о том, что состояние не изменилось, и, следовательно, повторный рендеринг не запускается.
Вы можете обновить свое состояние, как показано ниже, чтобы оно работало
.catch((e) => {
// If data can't be fetched, it probably means we are restarting
// services, so we updated the tasks array accordingly
setData((prev) => {
for (var t of prev.tasks) {
if (t['id'] === "restarting") {
t['status'] = 'running'
}
else if (t['status'] == "running") {
t['status'] = 'finished'
}
}
// The expected data is logged here
console.info(prev)
return {...prev}
})
})
Однако лучший способ обновить состояние - сделать это неизменным способом.
.catch((e) => {
// If data can't be fetched, it probably means we are restarting
// services, so we updated the tasks array accordingly
setData((prev) => ({
...prev,
tasks: prev.tasks.map((task) => {
if (task.id === "restarting") {
return { ...task, status: 'running'}
}
else if (task.id === "running") {
return { ...task, status: 'finished'}
}
return task
})
}))
})
Под мутацией я подразумеваю то, что вы изменяете объект состояния в той же ссылке, для обновлений состояния вы должны создать новую ссылку. Прочтите о неизменности в javascript
Ха, тогда все наоборот, обновление должно быть другим объектом, а я просто изменял возвращаемый. Вы спасли мне день, и я обязательно найду какую-нибудь литературу о неизменности!
Спасибо, сэр, действительно работает. Если бы я только понял почему! Итак, вы сказали, что я изменяю состояние: означает ли это, что я возвращаю новый, измененный объект? т.е. ссылка на этот объект отличается, и поскольку оригинал не был изменен, реакция не перерисовывается?