道具在单次刷新中更新 3 次
Props gets updated 3 times in single refresh
我是 react.I 的新手,我从一开始就尝试使用 react-redux 风格。
以下是我为简单的产品列表页面尝试的内容。
在我的 App.js 中用于检查用户是否仍处于登录状态。
class App extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
if (isUserAuthenticated() === true) {
const token = window.localStorage.getItem('jwt');
if (token) {
agent.setToken(token);
}
this.props.appLoad(token ? token : null, this.props.history);
}
}
render() {
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
isUserAuthenticated() === true
? <Component {...props} />
: <Redirect to='/logout' />
)} />
)
return (
<React.Fragment>
<Router>
<Switch>
{routes.map((route, idx) =>
route.ispublic ?
<Route path={route.path} component={withLayout(route.component)} key={idx} />
:
<PrivateRoute path={route.path} component={withLayout(route.component)} key={idx} />
)}
</Switch>
</Router>
</React.Fragment>
);
}
}
export default withRouter(connect(mapStatetoProps, { appLoad })(App));
在我的 action.js appLoaded 操作中如下
export const appLoad = (token, history) => {
return {
type: APP_LOAD,
payload: { token, history }
}
}
reducer.js 为它
import { APP_LOAD, APP_LOADED, APP_UNLOADED, VARIFICATION_FAILED } from './actionTypes';
const initialState = {
appName: 'Etsync',
token: null,
user: null,
is_logged_in: false
}
const checkLogin = (state = initialState, action) => {
switch (action.type) {
case APP_LOAD:
state = {
...state,
user: action.payload,
is_logged_in: false
}
break;
case APP_LOADED:
state = {
...state,
user: action.payload.user,
token: action.payload.user.token,
is_logged_in: true
}
break;
case APP_UNLOADED:
state = initialState
break;
case VARIFICATION_FAILED:
state = {
...state,
user: null,
}
break;
default:
state = { ...state };
break;
}
return state;
}
export default checkLogin;
并且在 Saga.js 中,我观察了每个 appLoad 操作并执行了下面的操作
import { takeEvery, fork, put, all, call } from 'redux-saga/effects';
import { APP_LOAD } from './actionTypes';
import { appLoaded, tokenVerificationFailed } from './actions';
import { unsetLoggeedInUser } from '../../helpers/authUtils';
import agent from '../agent';
function* checkLogin({ payload: { token, history } }) {
try {
let response = yield call(agent.Auth.current, token);
yield put(appLoaded(response));
} catch (error) {
if (error.message) {
unsetLoggeedInUser();
yield put(tokenVerificationFailed());
history.push('/login');
} else if (error.response.text === 'Unauthorized') {
unsetLoggeedInUser();
yield put(tokenVerificationFailed());
}
}
}
export function* watchUserLogin() {
yield takeEvery(APP_LOAD, checkLogin)
}
function* commonSaga() {
yield all([fork(watchUserLogin)]);
}
export default commonSaga;
在那之后,对于 productLists 页面,我的代码如下
//importing part
class EcommerceProductEdit extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
**//seeing the props changes**
console.log(this.props);
this.props.activateAuthLayout();
if (this.props.user !== null && this.props.user.shop_id)
this.props.onLoad({
payload: Promise.all([
agent.Products.get(this.props.user),
])
});
}
render() {
return (
// JSX code removed for making code shorter
);
}
}
const mapStatetoProps = state => {
const { user, is_logged_in } = state.Common;
const { products } = state.Products.products.then(products => {
return products;
});
return { user, is_logged_in, products };
}
export default connect(mapStatetoProps, { activateAuthLayout, onLoad })(EcommerceProductEdit);
但是在 componentDidMount 的这个页面中,如果我记录道具,我会在控制台中获得三次。如
休息一切正常。我只是担心,我正在做的代码不符合标准。
任何类型的见解都受到高度赞赏。
谢谢
这是因为您以无法批处理渲染的方式发生了三个状态更新。
您首先在没有数据的情况下进行渲染。您可以在第一个日志中看到这一点。没有用户,他们没有登录。
然后你得到一个用户。您可以在第二个日志中看到这一点。有一个用户,但他们没有登录。
然后让他们登录。您可以在第三个日志中看到这一点。有一个用户,他们已登录。
如果这些都是在单独的步骤中完成的,并且每一步都更新 Redux 存储,您将在每一步之间进行渲染。但是,如果您获得了用户,并让他们登录,然后在同一时间范围内将他们存储在 redux 状态中,您只会渲染额外的时间。请记住,React 和 Redux 是大量异步库,它们尝试使用批处理来确保在同一时间范围内完成的事情只会导致一次渲染,但有时您需要同时处理多个网络步骤。所以不,你没有做错任何事,你只是有很多步骤不能轻易地放在同一个框架中,因为它们依赖于一些具有自己的异步获取的外部资源。
我是 react.I 的新手,我从一开始就尝试使用 react-redux 风格。 以下是我为简单的产品列表页面尝试的内容。
在我的 App.js 中用于检查用户是否仍处于登录状态。
class App extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
if (isUserAuthenticated() === true) {
const token = window.localStorage.getItem('jwt');
if (token) {
agent.setToken(token);
}
this.props.appLoad(token ? token : null, this.props.history);
}
}
render() {
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={(props) => (
isUserAuthenticated() === true
? <Component {...props} />
: <Redirect to='/logout' />
)} />
)
return (
<React.Fragment>
<Router>
<Switch>
{routes.map((route, idx) =>
route.ispublic ?
<Route path={route.path} component={withLayout(route.component)} key={idx} />
:
<PrivateRoute path={route.path} component={withLayout(route.component)} key={idx} />
)}
</Switch>
</Router>
</React.Fragment>
);
}
}
export default withRouter(connect(mapStatetoProps, { appLoad })(App));
在我的 action.js appLoaded 操作中如下
export const appLoad = (token, history) => {
return {
type: APP_LOAD,
payload: { token, history }
}
}
reducer.js 为它
import { APP_LOAD, APP_LOADED, APP_UNLOADED, VARIFICATION_FAILED } from './actionTypes';
const initialState = {
appName: 'Etsync',
token: null,
user: null,
is_logged_in: false
}
const checkLogin = (state = initialState, action) => {
switch (action.type) {
case APP_LOAD:
state = {
...state,
user: action.payload,
is_logged_in: false
}
break;
case APP_LOADED:
state = {
...state,
user: action.payload.user,
token: action.payload.user.token,
is_logged_in: true
}
break;
case APP_UNLOADED:
state = initialState
break;
case VARIFICATION_FAILED:
state = {
...state,
user: null,
}
break;
default:
state = { ...state };
break;
}
return state;
}
export default checkLogin;
并且在 Saga.js 中,我观察了每个 appLoad 操作并执行了下面的操作
import { takeEvery, fork, put, all, call } from 'redux-saga/effects';
import { APP_LOAD } from './actionTypes';
import { appLoaded, tokenVerificationFailed } from './actions';
import { unsetLoggeedInUser } from '../../helpers/authUtils';
import agent from '../agent';
function* checkLogin({ payload: { token, history } }) {
try {
let response = yield call(agent.Auth.current, token);
yield put(appLoaded(response));
} catch (error) {
if (error.message) {
unsetLoggeedInUser();
yield put(tokenVerificationFailed());
history.push('/login');
} else if (error.response.text === 'Unauthorized') {
unsetLoggeedInUser();
yield put(tokenVerificationFailed());
}
}
}
export function* watchUserLogin() {
yield takeEvery(APP_LOAD, checkLogin)
}
function* commonSaga() {
yield all([fork(watchUserLogin)]);
}
export default commonSaga;
在那之后,对于 productLists 页面,我的代码如下
//importing part
class EcommerceProductEdit extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentDidMount() {
**//seeing the props changes**
console.log(this.props);
this.props.activateAuthLayout();
if (this.props.user !== null && this.props.user.shop_id)
this.props.onLoad({
payload: Promise.all([
agent.Products.get(this.props.user),
])
});
}
render() {
return (
// JSX code removed for making code shorter
);
}
}
const mapStatetoProps = state => {
const { user, is_logged_in } = state.Common;
const { products } = state.Products.products.then(products => {
return products;
});
return { user, is_logged_in, products };
}
export default connect(mapStatetoProps, { activateAuthLayout, onLoad })(EcommerceProductEdit);
但是在 componentDidMount 的这个页面中,如果我记录道具,我会在控制台中获得三次。如
休息一切正常。我只是担心,我正在做的代码不符合标准。 任何类型的见解都受到高度赞赏。 谢谢
这是因为您以无法批处理渲染的方式发生了三个状态更新。
您首先在没有数据的情况下进行渲染。您可以在第一个日志中看到这一点。没有用户,他们没有登录。 然后你得到一个用户。您可以在第二个日志中看到这一点。有一个用户,但他们没有登录。 然后让他们登录。您可以在第三个日志中看到这一点。有一个用户,他们已登录。
如果这些都是在单独的步骤中完成的,并且每一步都更新 Redux 存储,您将在每一步之间进行渲染。但是,如果您获得了用户,并让他们登录,然后在同一时间范围内将他们存储在 redux 状态中,您只会渲染额外的时间。请记住,React 和 Redux 是大量异步库,它们尝试使用批处理来确保在同一时间范围内完成的事情只会导致一次渲染,但有时您需要同时处理多个网络步骤。所以不,你没有做错任何事,你只是有很多步骤不能轻易地放在同一个框架中,因为它们依赖于一些具有自己的异步获取的外部资源。