一次redux presist导致的ssr问题
问题
在使用redux presist的时候,如果这样写StoreProvider:
"use client"
import { persistor, store } from "@/store"
import { ReactNode } from "react"
import { Provider } from "react-redux"
import { PersistGate } from "redux-persist/integration/react"
export default function StoreProvider({ children }: { children: ReactNode }){
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
{children}
</PersistGate>
</Provider>
)
}
会导致children无法在服务端被渲染。
解决方案
改写成:
"use client"
import { persistor, store } from "@/store"
import { ReactNode } from "react"
import { Provider } from "react-redux"
import { PersistGate } from "redux-persist/integration/react"
export default function StoreProvider({ children }: { children: ReactNode }){
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
{() => children}
</PersistGate>
</Provider>
)
}
原理
PresistGate使用了bootstrapped这个state,并且在componentDidMount中设置。
而componentDidMount并不在服务端运行。于是就渲染了loading中的内容。
代码:
componentDidMount() {
this._unsubscribe = this.props.persistor.subscribe(
this.handlePersistorState
)
this.handlePersistorState()
}
handlePersistorState = () => {
const { persistor } = this.props
let { bootstrapped } = persistor.getState()
if (bootstrapped) {
if (this.props.onBeforeLift) {
Promise.resolve(this.props.onBeforeLift())
.finally(() => this.setState({ bootstrapped: true }))
} else {
this.setState({ bootstrapped: true })
}
this._unsubscribe && this._unsubscribe()
}
}
render() {
if (process.env.NODE_ENV !== 'production') {
if (typeof this.props.children === 'function' && this.props.loading)
console.error(
'redux-persist: PersistGate expects either a function child or loading prop, but not both. The loading prop will be ignored.'
)
}
if (typeof this.props.children === 'function') {
return this.props.children(this.state.bootstrapped)
}
return this.state.bootstrapped ? this.props.children : this.props.loading
}cover
但是如果children是一个funcion,就会执行:
if (typeof this.props.children === 'function') {
return this.props.children(this.state.bootstrapped)
}
这与this.state.bootstrapped无关。