React Router Protected Routes 在获取用户令牌之前触发
React Router Protected Routes firing before getting user token
我有一个 React 应用程序,它会在 componentWillMount()
上触发动作创建者从存储的令牌中获取当前用户:
App.js
...
async componentWillMount() {
const token = localStorage.getItem("token");
if (token) {
await this.props.fetchUser();
}
}
...
然后,在同一个 App.js
文件中,我定义了一些路由。为简单起见,我将显示两条路线:
App.js
...
render() {
return (
<Router>
<div>
<Reboot />
<Route component={Header} />
<Route exact path="/" component={Landing} />
<ProtectedRoute
isSignedIn={this.props.authenticated.jwtToken}
path="/books"
component={BookList}
/>
</div>
</Router>
);
}
...
在 Header
组件中,我有一个重定向到 /books
的按钮,点击后会在用户登录时正确显示图书列表。
当我尝试从浏览器直接转到 http://localhost:3000/books
URL 时出现问题(即不是通过单击按钮)。 ProtectedRoute
组件似乎在 fetchUser()
returns authenticated
状态对象之前呈现,因此将重定向回主登录页面。
这是 ProtectedRoute
组件:
export const ProtectedRoute = ({
component: Component,
jwtToken,
isSignedIn,
...rest
}) => {
return (
<Route
{...rest}
render={props =>
isSignedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location, message: "You need to sign in" }
}}
/>
)
}
/>
);
};
这是 fetchUser()
的动作创建器:
export const fetchUser = () => async dispatch => {
await dispatch({ type: FETCHING_USER });
try {
const res = await axios.get(`${API_URL}/api/current_user`, {
headers: { authorization: localStorage.getItem("token") }
});
await dispatch({ type: FETCH_USER, payload: res.data });
} catch (err) {
// dispatch error action types
}
};
我认为通过使用 async/await
语法,我可以维护已调度操作的顺序...
有人可以告诉我我做错了什么吗?理想情况下,我可以直接从浏览器到达 /books
路线,而无需单击按钮。
在 componentWillMount
中调用异步操作不会阻止它在操作完成之前呈现。
在你的情况下,这与在 componentDidMount
中执行没有什么不同(这也是为什么 componentWillMount
在 React 17 中将是 deprecated)。
您必须在 fetchUser
完成之前决定向用户显示什么(在慢速连接上可能需要几秒钟)。
也许是旋转器?
我有一个 React 应用程序,它会在 componentWillMount()
上触发动作创建者从存储的令牌中获取当前用户:
App.js
...
async componentWillMount() {
const token = localStorage.getItem("token");
if (token) {
await this.props.fetchUser();
}
}
...
然后,在同一个 App.js
文件中,我定义了一些路由。为简单起见,我将显示两条路线:
App.js
...
render() {
return (
<Router>
<div>
<Reboot />
<Route component={Header} />
<Route exact path="/" component={Landing} />
<ProtectedRoute
isSignedIn={this.props.authenticated.jwtToken}
path="/books"
component={BookList}
/>
</div>
</Router>
);
}
...
在 Header
组件中,我有一个重定向到 /books
的按钮,点击后会在用户登录时正确显示图书列表。
当我尝试从浏览器直接转到 http://localhost:3000/books
URL 时出现问题(即不是通过单击按钮)。 ProtectedRoute
组件似乎在 fetchUser()
returns authenticated
状态对象之前呈现,因此将重定向回主登录页面。
这是 ProtectedRoute
组件:
export const ProtectedRoute = ({
component: Component,
jwtToken,
isSignedIn,
...rest
}) => {
return (
<Route
{...rest}
render={props =>
isSignedIn ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/",
state: { from: props.location, message: "You need to sign in" }
}}
/>
)
}
/>
);
};
这是 fetchUser()
的动作创建器:
export const fetchUser = () => async dispatch => {
await dispatch({ type: FETCHING_USER });
try {
const res = await axios.get(`${API_URL}/api/current_user`, {
headers: { authorization: localStorage.getItem("token") }
});
await dispatch({ type: FETCH_USER, payload: res.data });
} catch (err) {
// dispatch error action types
}
};
我认为通过使用 async/await
语法,我可以维护已调度操作的顺序...
有人可以告诉我我做错了什么吗?理想情况下,我可以直接从浏览器到达 /books
路线,而无需单击按钮。
在 componentWillMount
中调用异步操作不会阻止它在操作完成之前呈现。
在你的情况下,这与在 componentDidMount
中执行没有什么不同(这也是为什么 componentWillMount
在 React 17 中将是 deprecated)。
您必须在 fetchUser
完成之前决定向用户显示什么(在慢速连接上可能需要几秒钟)。
也许是旋转器?