隔了一天才搞清楚。
簡述
當時的情境是我想在 App 包裹一層 <Loading.Provider>,接著再透過子元件去呼叫 setIsLoading 來更新 state,像這樣:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | const [isLoading, setIsloading] = useState(false);
 return (
 <ThemeProvider theme={theme}>
 <GlobalStyle />
 {/* loading context */}
 <Loading.Provider value={[isLoading, setIsloading]}>
 <AuthContext.Provider value={{ user, setUser }}>
 <Router>
 <NavBar />
 <Routes>
 <Route path="/" element={<HomePage />} />
 <Route path="/about" element={<AboutPage />} />
 <Route path="/categories" element={<CategoriesPage />} />
 <Route path="/posts" element={<PostsPage />} />
 <Route path="/posts/:id" element={<SinglePostPage />} />
 <Route path="/log-in" element={<LoginPage />} />
 <Route path="/sign-up" element={<SignUpPage />} />
 <Route path="/test" element={<TestPage />} />
 </Routes>
 {/* loading component */}
 <StyledLoader
 active={isLoading}
 spinner={true}
 text="Loading your content..."
 ></StyledLoader>
 </Router>
 </AuthContext.Provider>
 </Loading.Provider>
 </ThemeProvider>
 )
 
 | 
接著我在子元件裡面這樣寫:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | export default function HomePage() {
 const [isLoading, setIsLoading] =useContext(Loading)
 const [posts, setPosts] = useState([]);
 
 
 setIsLoading(true);
 
 useEffect(() => {
 getAllPosts().then((data) => {
 setPosts(data);
 
 setIsLoading(false);
 });
 }, [setIsLoading]);
 
 
 }
 
 | 
接著就噴錯誤了:

Warning 的大意是說我不應該在 render 子元件的時候去更新 state。我一開始沒有很懂這什麼意思,不過後來仔細想一下流程後就明白了。
總之這是因為我在 render 子元件的時候去更新了 state,這時候就會觸發 App 重新 render,然後 render 子元件的時候又再更新了 state,觸發 App 重新 render … 
大概就跟這張圖的意思一樣:

所以要避開這種:
- 在 render 時更新 state 的行為
- 在 render 時更新 state 的行為
- 在 render 時更新 state 的行為
這個真的很重要QQ,請務必搞清楚。
最後呢,這個範例的正確做法應該是這樣:
| 12
 3
 4
 5
 6
 7
 8
 
 | useEffect(() => {
 setIsLoading(true);
 getAllPosts().then((data) => {
 setPosts(data);
 setIsLoading(false);
 });
 }, [setIsLoading]);
 
 | 
希望以後別再踩到同樣的雷。