[英]ReactJS Context re-render after a fetch with useEffect hook
I am currently trying to pass data with my context provider
through the entire application but the hook that triggers, only returns it's initial value and doesn't re-trigger .我目前正在尝试通过整个应用程序使用我的
context provider
传递数据,但触发的钩子仅返回它的初始值并且不会重新触发。
This is my application layout inside my main App
component which doesn't hold any state.这是我的主要
App
组件中的应用程序布局,它不包含任何 state。
class App extends Component {
render() {
return (
<div>
<BrowserRouter>
<UserContextProvider>
<div className="container">
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/login" component={LoginPage} />
<PrivateRoute exact path="/secret-page" component={SecretPage} />
</Switch>
</div>
</UserContextProvider>
</BrowserRouter>
</div>
);
}
}
export default App;
Whenever the App
component renders for the first time, it triggers the UserContextProvider
which fires an onEffect
hook.每当
App
组件第一次呈现时,它都会触发UserContextProvider
,它会触发一个onEffect
钩子。 This hook tries to fetch some data but since the user is not logged in, it just returns it's original value []
.这个钩子试图获取一些数据,但由于用户没有登录,它只是返回它的原始值
[]
。
Here is the Context Provider这是上下文提供者
const UserContextProvider = ({children}) => {
const [userSettings, setUserSettings] = useState([]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
if (userid !== null) {
fetch(
process.env.REACT_APP_API_URL + "/authenticated/get-permissions",
requestOptions
)
.then(response => response.json())
.then(response => {
setUserSettings(response.data);
setIsLoggedIn(true);
})
.catch(error => console.log(error));
} else {
console.log(userSettings);
setIsLoggedIn(false);
}
}, []);
return (
<UserContext.Provider value={userSettings}>{children}</UserContext.Provider>
);
};
Now when the code above fires initially, the userid
value is null
but after authentication in the LoginPage
child component, it changes to a token.现在,当上面的代码最初触发时,
userid
值为null
但在LoginPage
子组件中进行身份验证后,它会更改为令牌。 My issue is that even though userid
's value changes after login, the hook doesn't fire again.我的问题是,即使
userid
的值在登录后发生变化,钩子也不会再次触发。
I just want to mention that I get the userid
value from local storage in a separate file and import it.我只想提一下,我从本地存储中的单独文件中获取
userid
值并将其导入。
I've tried setting the userid
value in the empty array argument inside the function but that doesn't work.我尝试在 function 内的空数组参数中设置
userid
值,但这不起作用。
How can I make my useEffect
hook to fire again after the userid
value has changed?在
userid
值更改后,如何使我的useEffect
挂钩再次触发?
--- EDIT----- - - 编辑 - - -
userid
is import from another file called fetchRequestOptions
in this way: userid
是以这种方式从另一个名为fetchRequestOptions
的文件中导入的:
import {requestOptions, userid} from "./fetchRequestOptions";
Inside my fetchRequestOptions
file I have the following code:在我的
fetchRequestOptions
文件中,我有以下代码:
let userid = localStorage.getItem("userid");
let accessToken = localStorage.getItem("accesstoken");
let requestOptions ={ <my request options are here>}
In order for the hook that uses userid
to re-run when it changes, you need to keep it inside a state.为了使用
userid
的钩子在更改时重新运行,您需要将其保存在 state 中。 Then, LoginPage
needs to be connected to the Context and use setUserid
to update its value.然后,
LoginPage
需要连接到 Context 并使用setUserid
来更新它的值。
const UserContextProvider = ({ children }) => {
const [userSettings, setUserSettings] = useState([]);
const [isLoggedIn, setIsLoggedIn] = useState(false);
// If you are reading directly from localstorage you might
// want to use localStorage.getItem("userid") as the initial value
const [userid, setUserid] = useState(null);
useEffect(() => {
// ...
}, [userid]);
return (
<UserContext.Provider value={{ userSettings, setUserid }}>
{children}
</UserContext.Provider>
);
};
The key is that userid
needs to be inside a state, this way it can trigger a new render in any Component where you need its latest value.关键是
userid
需要在 state 中,这样它可以在您需要其最新值的任何组件中触发新的渲染。
You might find it cleaner to have a specific custom hook, inside your Context, that handles the logic for the userid (fetch and update).您可能会发现在您的 Context 中拥有一个特定的自定义钩子会更简洁,它处理用户 ID 的逻辑(获取和更新)。 This is a good option but it only makes
userid
available inside this context.这是一个不错的选择,但它只使
userid
在此上下文中可用。 If you need to use it somewhere else you will need to export it from the context value
prop.如果您需要在其他地方使用它,则需要从上下文
value
道具中导出它。
const useUserid = () => {
const [userid, setUserid] = useState(null);
useEffect(() => {
const fetched_userid = //...
setUserid(fetched_userid);
}, []);
return userid;
};
const UserContextProvider = ({ children }) => {
// ...
const userid = useUserid();
useEffect(() => {
// ...
}, [userid]);
return (
<UserContext.Provider value={userSettings}>{children}</UserContext.Provider>
);
};
Passing an empty array [] in an useEffect hook means that (as per React documentation)在 useEffect 挂钩中传递一个空数组 [] 意味着(根据 React 文档)
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument.
如果你想运行一个效果并且只清理一次(在挂载和卸载时),你可以传递一个空数组([])作为第二个参数。 This tells React that your effect doesn't depend on any values from props or state, so it never needs to re-run
这告诉 React 你的效果不依赖于 props 或 state 的任何值,所以它永远不需要重新运行
So, we need to pass props/state that acts as trigger for effect to re-render.因此,我们需要传递作为重新渲染效果触发器的道具/状态。
pass userid
as an argument in the dependency array of the useEffect.将
userid
作为参数传递到 useEffect 的依赖数组中。 This ensures the effect is run whenever userid
changes.这样可以确保在
userid
更改时运行效果。
useEffect(() => {
...
}, [userid]);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.