React hooks app saga 使用 history.push 然后不能正确渲染组件
React hooks app saga use history.push then doesn't render component correctly
感谢您查看此问题。我用 typescript 写了一个 react hooks login demo.I 有一些问题。
1. 我在登录成功时使用history.push('/home')
。但页面呈现 Notification
组件。
2. 在 login saga 中进行路由器跳转是更好的方法吗?其他方法是在登录 component.when success.use useHistory
挂钩中执行 it.I 更喜欢第一种方法。我是后端程序员新来写frontend.so不知道什么方法最好
services/history.ts
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;
我的路由器
import React, { Suspense } from 'react';
import { Route, Switch, Router } from 'react-router-dom';
import Loading from '@components/Loading';
import history from '@services/history';
import routes from './routes';
const renderRoutes = routes.map(({ path, exact, component, key }) => (
<Route exact={exact || false} path={path} key={key} component={component} />
));
const Routers: React.FC = () => (
<Router history={history}>
<Suspense fallback={<Loading />}>
<Switch>{renderRoutes}</Switch>
</Suspense>
</Router>
);
export default Routers;
// my routes
import { lazy } from 'react';
const routes = [
{
path: '/',
key: 'login',
exact: true,
component: lazy(() => import('./../views/login')),
},
{
path: '/home',
key: 'home',
component: lazy(() => import('./../views/home')),
},
];
export default routes;
我的login.tsx
const Login: React.FC = () => {
const [loading, setLoading] = useState(false);
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
const dispatch = useDispatch();
const handleSubmit = (values: any) => {
setLoading(true);
const { username, password } = values;
dispatch(loginRequest(username, password));
};
return (
<div className="login-page">
<Form name="login" className="login-form" onFinish={handleSubmit}>
<p className="login-title"> Go React</p>
<FormItem
name="username"
rules={[
{ required: true, message: 'Please input your Username!' },
{ min: 4, message: 'min length of username is 4' },
{ max: 12, message: 'max length of username is 12' },
]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Username"
size="large"
/>
</FormItem>
<FormItem
name="password"
rules={[
{ required: true, message: 'Please input your Password!' },
{ min: 4, message: 'min length of password is 4' },
{ max: 12, message: 'max length of password is 12' },
]}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
size="large"
/>
</FormItem>
<FormItem>
<Button
htmlType="submit"
type="primary"
className="login-button"
size="large"
>
<Spin indicator={antIcon} spinning={loading} />
{loading ? ' Logging in' : ' Login'}
</Button>
</FormItem>
</Form>
</div>
);
};
export default Login;
handlesubmit 将发送一个 dispatch,saga 将关注这个。
saga.ts
import { fork, all, take, call, put, cancel } from 'redux-saga/effects';
import { message } from 'antd';
import fetchLogin from '@services/login';
import TokenStorage from '@utils/storage';
import ILoginResponseData from '@models/login';
import UserModel from '@models/user';
import history from '@services/history';
import {
loginFailed,
loginSuccess,
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILED,
} from './action';
function* LoginRequestSaga(username: string, password: string) {
try {
const result: ILoginResponseData = yield call(
fetchLogin,
username,
password
);
if (result.code === '1') {
TokenStorage.storeToken(result.token);
message.success(result.msg);
history.push('/home'); <-------------I do history jump in here.
const user = UserModel.getUser(result.token);
yield put(loginSuccess(user));
} else {
message.error(result.msg);
yield put(loginFailed());
}
} catch (err) {
message.error(err);
yield put(loginFailed());
}
}
function* watchLogin() {
while (true) {
const { authData } = yield take(LOGIN_REQUEST);
const task = yield fork(
LoginRequestSaga,
authData.username,
authData.password
);
const action = yield take([LOGIN_SUCCESS, LOGIN_FAILED]);
if (action.type === LOGIN_SUCCESS) {
yield cancel(task);
}
}
}
export default function* rootSaga() {
yield all([watchLogin()]);
}
我的主页组件
import React from 'react';
import { useSelector } from 'react-redux';
import { RootState } from '@store/reducer';
const Home: React.FC = () => {
const user = useSelector((state: RootState) => state.user);
return <div>Current User:{user.name}</div>;
};
export default Home;
登录成功时。该页面未正确显示组件。
"dependencies": {
"@ant-design/icons": "^4.1.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/history": "^4.7.6",
"@types/jest": "^24.0.0",
"@types/jwt-decode": "^2.2.1",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.5",
"@types/store": "^2.0.2",
"antd": "^4.2.5",
"axios": "^0.19.2",
"history": "^5.0.0",
"jwt-decode": "^2.2.0",
"node-sass": "^4.14.1",
"react": "^16.13.1",
"react-app-rewire-alias": "^0.1.6",
"react-app-rewired": "^2.1.6",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"redux": "^4.0.5",
"redux-saga": "^1.1.3",
"typescript": "~3.7.2"
},
@xiaodonghuan。 history 包的最新版本“5.0.0”中有一些重大变化。现在,您可以将其版本更改为稳定版本,即可以使用的“4.10.1”。
使用以下命令更改历史版本
npm install history@4.10.1
希望它能奏效。
感谢您查看此问题。我用 typescript 写了一个 react hooks login demo.I 有一些问题。
1. 我在登录成功时使用history.push('/home')
。但页面呈现 Notification
组件。
2. 在 login saga 中进行路由器跳转是更好的方法吗?其他方法是在登录 component.when success.use useHistory
挂钩中执行 it.I 更喜欢第一种方法。我是后端程序员新来写frontend.so不知道什么方法最好
services/history.ts
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
export default history;
我的路由器
import React, { Suspense } from 'react';
import { Route, Switch, Router } from 'react-router-dom';
import Loading from '@components/Loading';
import history from '@services/history';
import routes from './routes';
const renderRoutes = routes.map(({ path, exact, component, key }) => (
<Route exact={exact || false} path={path} key={key} component={component} />
));
const Routers: React.FC = () => (
<Router history={history}>
<Suspense fallback={<Loading />}>
<Switch>{renderRoutes}</Switch>
</Suspense>
</Router>
);
export default Routers;
// my routes
import { lazy } from 'react';
const routes = [
{
path: '/',
key: 'login',
exact: true,
component: lazy(() => import('./../views/login')),
},
{
path: '/home',
key: 'home',
component: lazy(() => import('./../views/home')),
},
];
export default routes;
我的login.tsx
const Login: React.FC = () => {
const [loading, setLoading] = useState(false);
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
const dispatch = useDispatch();
const handleSubmit = (values: any) => {
setLoading(true);
const { username, password } = values;
dispatch(loginRequest(username, password));
};
return (
<div className="login-page">
<Form name="login" className="login-form" onFinish={handleSubmit}>
<p className="login-title"> Go React</p>
<FormItem
name="username"
rules={[
{ required: true, message: 'Please input your Username!' },
{ min: 4, message: 'min length of username is 4' },
{ max: 12, message: 'max length of username is 12' },
]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="Username"
size="large"
/>
</FormItem>
<FormItem
name="password"
rules={[
{ required: true, message: 'Please input your Password!' },
{ min: 4, message: 'min length of password is 4' },
{ max: 12, message: 'max length of password is 12' },
]}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
size="large"
/>
</FormItem>
<FormItem>
<Button
htmlType="submit"
type="primary"
className="login-button"
size="large"
>
<Spin indicator={antIcon} spinning={loading} />
{loading ? ' Logging in' : ' Login'}
</Button>
</FormItem>
</Form>
</div>
);
};
export default Login;
handlesubmit 将发送一个 dispatch,saga 将关注这个。 saga.ts
import { fork, all, take, call, put, cancel } from 'redux-saga/effects';
import { message } from 'antd';
import fetchLogin from '@services/login';
import TokenStorage from '@utils/storage';
import ILoginResponseData from '@models/login';
import UserModel from '@models/user';
import history from '@services/history';
import {
loginFailed,
loginSuccess,
LOGIN_REQUEST,
LOGIN_SUCCESS,
LOGIN_FAILED,
} from './action';
function* LoginRequestSaga(username: string, password: string) {
try {
const result: ILoginResponseData = yield call(
fetchLogin,
username,
password
);
if (result.code === '1') {
TokenStorage.storeToken(result.token);
message.success(result.msg);
history.push('/home'); <-------------I do history jump in here.
const user = UserModel.getUser(result.token);
yield put(loginSuccess(user));
} else {
message.error(result.msg);
yield put(loginFailed());
}
} catch (err) {
message.error(err);
yield put(loginFailed());
}
}
function* watchLogin() {
while (true) {
const { authData } = yield take(LOGIN_REQUEST);
const task = yield fork(
LoginRequestSaga,
authData.username,
authData.password
);
const action = yield take([LOGIN_SUCCESS, LOGIN_FAILED]);
if (action.type === LOGIN_SUCCESS) {
yield cancel(task);
}
}
}
export default function* rootSaga() {
yield all([watchLogin()]);
}
我的主页组件
import React from 'react';
import { useSelector } from 'react-redux';
import { RootState } from '@store/reducer';
const Home: React.FC = () => {
const user = useSelector((state: RootState) => state.user);
return <div>Current User:{user.name}</div>;
};
export default Home;
登录成功时。该页面未正确显示组件。
"dependencies": {
"@ant-design/icons": "^4.1.0",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/history": "^4.7.6",
"@types/jest": "^24.0.0",
"@types/jwt-decode": "^2.2.1",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
"@types/react-redux": "^7.1.9",
"@types/react-router-dom": "^5.1.5",
"@types/store": "^2.0.2",
"antd": "^4.2.5",
"axios": "^0.19.2",
"history": "^5.0.0",
"jwt-decode": "^2.2.0",
"node-sass": "^4.14.1",
"react": "^16.13.1",
"react-app-rewire-alias": "^0.1.6",
"react-app-rewired": "^2.1.6",
"react-dom": "^16.13.1",
"react-redux": "^7.2.0",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"redux": "^4.0.5",
"redux-saga": "^1.1.3",
"typescript": "~3.7.2"
},
@xiaodonghuan。 history 包的最新版本“5.0.0”中有一些重大变化。现在,您可以将其版本更改为稳定版本,即可以使用的“4.10.1”。
使用以下命令更改历史版本
npm install history@4.10.1
希望它能奏效。