javascript - "React, Hooks sıralamasında bir değişiklik tespit etti" ama Hooks sırasıyla çağrılıyor gibi görünüyor
Context ve Reducers'ı React’in hook’ları aracılığıyla kullanmaya çalışıyorum ve hook’ların sırasının sabit olmamasıyla ilgili sorunlar yaşıyorum. Anladığım kadarıyla, useHook(…) sırası aynı kaldığı sürece, döndürülen durum/güncelleme fonksiyonu/reducer’ı herhangi bir kontrol akışında çağırmak sorun değil. Aksi takdirde, hook’ları FunctionComponent’lerin en başında çağırıyorum.
Bunu bir döngüde Days mi üretiyorum? Yoksa başka bir şeyi mi kaçırıyorum?
Warning: React has detected a change in the order of Hooks
called by Container. This will lead to bugs and errors if not fixed. For
more information, read the Rules of Hooks:
https://reactjs.org/docs/hooks-rules.html
Previous render Next render
------------------------------------------------------
1. useContext useContext
2. undefined useRef
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Container’ın tam sürümü aşağıdadır. Day’den bir alıntı aşağıda verilmiştir ve react-dnd’nin useDrop’undan bir referansa sahiptir.
export const Container: FunctionComponent<Props> = () => {
let events = useContext(State.StateContext)
//let events: Array<Event.Event> = [] <- with this, no warning
const getDaysEvents = (day: Event.Time, events: Array<Event.Event>) => {
return events.map(e => {
const isTodays = e.startTime.hasSame(day, "day")
return isTodays && Event.Event({ dayHeight, event: e })
})
}
let days = []
for (let i = 0; i < 7; i++) {
const day = DateTime.today().plus({ days: i })
days.push(
<Day key={day.toISO()} height={dayHeight} date={day}>
{getDaysEvents(day, events)}
</Day>
)
}
return <div className="Container">{days}</div>
}
Day'den bir alıntı (Event de benzer şekilde bir useDrag kancası kullanır, tıpkı burada olduğu gibi en üst düzeyde çağrılır).
const Day: FunctionComponent<DayProps> = ({ date, height, children }) => {
const dispatch = useContext(State.DispatchContext)
const [{ isOver, offset }, dropRef] = useDrop({
// …uses the dispatch function within…
// …
})
// …
}
Cevap #1
Kısa devre mantığı kullanmam nedeniyle yazdığım bir bileşende bu aynı hata mesajıyla karşılaştım.
Bu bir hatayla sonuçlandı:
const x = useSelector(state => state.foo);
if (!x) { return ; }
const y = useSelector(state => state.bar);
Bunun nedeni, x doğru değere sahip olduğunda kancalar listesinin uzunluğunun 2 olması, ancak x yanlış değere sahip olduğunda listenin uzunluğunun 1 olmasıdır.
Hatası çözmek için tüm hook kullanımını herhangi bir erken sonlandırmadan önce koymam gerekiyordu.
const x = useSelector(state => state.foo);
const y = useSelector(state => state.bar);
if (!x) { return ; }
Cevap #2
Yorumumu bir cevap olarak yazıyorum:
Sorun, Event.Event() fonksiyonunu doğrudan çağırmanızdır, oysa bu bir React bileşenidir. Bu, fonksiyon içindeki hook çağrılarını Container parçası olarak ele alacak şekilde React'in davranmasına neden olur, halbuki siz bunların Event parçası olmasını istemiştiniz.
Çözüm JSX kullanmaktır:
return isTodays && <Event.Event dayHeight={dayHeight} event={e} />Bunun neden işe yaradığını, JSX'i ortaya çıkan JS koduyla değiştirdiğinizde daha net görürsünüz:
return isTodays && React.createElement(Event.Event, { dayHeight, event: e })Bkz. https://reactjs.org/docs/react-api.html#createelement. Fonksiyon bileşenlerini doğrudan çağırmak istemezsiniz, React'ın çalışma şekli, bileşen için her zaman bir referansı React'e vermeniz ve fonksiyonu doğru zamanda çağırmasına izin vermenizdir.
Cevap #3
Bu sorunun dışında başka bir nedenden dolayı, bu hatayı aldığınızda
Aslında bu, kanca uygulamaları için yapılan herhangi bir kötü uygulamadan dolayı olur
1 - Hook'ları Yalnızca Üst Düzeyde Çağırın
Hooks'u döngüler, koşullar veya iç içe fonksiyonlar içinde çağırmayın. Bunun yerine, Hooks'u her zaman React fonksiyonunuzun en üst seviyesinde kullanın.
NOT:
useStatekancalarınızı önce fonksiyonun en üstünde uygulayın
2 - Hook'ları Yalnızca React Fonksiyonlarından Çağırın
Hook'ları normal JavaScript fonksiyonlarından çağırmayın
3 - Test Sırasında Hata Almak
Bileşeni test ederken bu hatayı alırsanız, özel kancalarınızı nereye koyduğunuza dikkat edin (fonksiyonun en üstüne taşıyın)
En İyi Uygulama
kodunuzu lint etmek için eslint kullanın ve React Hooks Kuralları hatalarından kaçının
npm veya yarn ile paket yükleyin
npm install eslint-plugin-react-hooks --save-dev
