React 上下文的状态更新不会 re-render children
Updates to the state of React context don't re-render children
我正在通过 child 组件中的回调更新上下文中的共享状态,但这不会导致 re-render,从而导致 child 中的上下文具有初始值的组件直到下一个 re-render.
有没有办法在上下文提供程序中更新状态后强制更新 child 和 re-render?
我的上下文提供者:
const UserLocationContext = React.createContext()
export const useUserLocation = () => {
return useContext(UserLocationContext)
}
export const UserLocationProvider = ({ children }) => {
const [ipUserLocation, setIpUserLocation] = useState(null)
const updateIpUserLocation = (ipUserLocation) => {
setIpUserLocation(ipUserLocation)
console.log(ipUserLocation) //value is updated here immediately after the updateIpUserLocation call
}
return (
<UserLocationContext.Provider value = {{ipUserLocation, updateIpUserLocation}}>
{children}
</UserLocationContext.Provider>
)
}
export default UserLocationProvider
Child:
const LocationHandler = () => {
const {ipUserLocation, updateIpUserLocation} = useUserLocation()
useEffect(() => {
const ip_url = `https://api.freegeoip.app/json/`
const fetchIPLocation = async () => {
const result = await fetch(ip_url);
const json = await result.json();
updateIpUserLocation([json.latitude, json.longitude])
console.log(ipUserLocation) //value here remains null until next re-render
}
fetchIPLocation()
}, []);}
问题是 useState
是异步的,因此 ipUserLocation
值不会在 setIpUserLocation
被调用后立即更新。
对于修复,您可以将 ipUserLocation
添加为 useEffect
的依赖项,这将帮助您收听 ipUserLocation
在 LocationHandler
上的所有更改。
const LocationHandler = () => {
const {ipUserLocation, updateIpUserLocation} = useUserLocation()
useEffect(() => {
const ip_url = `https://api.freegeoip.app/json/`
const fetchIPLocation = async () => {
const result = await fetch(ip_url);
const json = await result.json();
updateIpUserLocation([json.latitude, json.longitude])
}
fetchIPLocation()
}, []);}
//add another `useEffect` with `ipUserLocation` in dependencies
useEffect(() => {
//TODO: You can do something with updated `ipUserLocation` here
console.log(ipUserLocation)
}, [ipUserLocation])
return ...
}
实际上,当您更新上下文状态时,child 组件会得到 re-rendered。发生这种情况是因为您正在使用 useContext 挂钩来监听对上下文所做的任何更改。你可以做些什么来向自己证明 child 得到 re-rendered 是在 child 组件中添加这个:
useEffect(() => {
console.log(ipUserLocation);
}, [ipUserLocation])
有了这个 useEffect,console.log 将 运行 每次 child 得到 re-rendered 和 ipUserLocation 已更改。
我正在通过 child 组件中的回调更新上下文中的共享状态,但这不会导致 re-render,从而导致 child 中的上下文具有初始值的组件直到下一个 re-render.
有没有办法在上下文提供程序中更新状态后强制更新 child 和 re-render?
我的上下文提供者:
const UserLocationContext = React.createContext()
export const useUserLocation = () => {
return useContext(UserLocationContext)
}
export const UserLocationProvider = ({ children }) => {
const [ipUserLocation, setIpUserLocation] = useState(null)
const updateIpUserLocation = (ipUserLocation) => {
setIpUserLocation(ipUserLocation)
console.log(ipUserLocation) //value is updated here immediately after the updateIpUserLocation call
}
return (
<UserLocationContext.Provider value = {{ipUserLocation, updateIpUserLocation}}>
{children}
</UserLocationContext.Provider>
)
}
export default UserLocationProvider
Child:
const LocationHandler = () => {
const {ipUserLocation, updateIpUserLocation} = useUserLocation()
useEffect(() => {
const ip_url = `https://api.freegeoip.app/json/`
const fetchIPLocation = async () => {
const result = await fetch(ip_url);
const json = await result.json();
updateIpUserLocation([json.latitude, json.longitude])
console.log(ipUserLocation) //value here remains null until next re-render
}
fetchIPLocation()
}, []);}
问题是 useState
是异步的,因此 ipUserLocation
值不会在 setIpUserLocation
被调用后立即更新。
对于修复,您可以将 ipUserLocation
添加为 useEffect
的依赖项,这将帮助您收听 ipUserLocation
在 LocationHandler
上的所有更改。
const LocationHandler = () => {
const {ipUserLocation, updateIpUserLocation} = useUserLocation()
useEffect(() => {
const ip_url = `https://api.freegeoip.app/json/`
const fetchIPLocation = async () => {
const result = await fetch(ip_url);
const json = await result.json();
updateIpUserLocation([json.latitude, json.longitude])
}
fetchIPLocation()
}, []);}
//add another `useEffect` with `ipUserLocation` in dependencies
useEffect(() => {
//TODO: You can do something with updated `ipUserLocation` here
console.log(ipUserLocation)
}, [ipUserLocation])
return ...
}
实际上,当您更新上下文状态时,child 组件会得到 re-rendered。发生这种情况是因为您正在使用 useContext 挂钩来监听对上下文所做的任何更改。你可以做些什么来向自己证明 child 得到 re-rendered 是在 child 组件中添加这个:
useEffect(() => {
console.log(ipUserLocation);
}, [ipUserLocation])
有了这个 useEffect,console.log 将 运行 每次 child 得到 re-rendered 和 ipUserLocation 已更改。