代码之家  ›  专栏  ›  技术社区  ›  Ebbs

React Redux在调度时重新呈现内部HOC不工作

  •  0
  • Ebbs  · 技术社区  · 7 年前

    我正忙着做一点概念验证,基本上要求是当用户还没有登录时,主页是一个登录屏幕,之后当身份验证成功后状态发生变化时,会显示一个包含相关内容的组件。

    我的第一个问题是让道具在最后一个场景中可用 then fetch this.props.dispatch 未定义。我使用了老的javascript技巧 console.log 然后 ,我可以看到它不再是未定义的,实际上是一个预期的函数。

    我现在的问题是 dispatch 被称为。但是,如果我手动刷新页面,它将显示 AuthenticatedPartialPage 组件,因为 localstorage 人口增加了。

    我的理解是 派遣 被调用后,条件语句将被重新计算并 认证部分页

    感觉好像少了什么东西 派遣

    import React from 'react';
    import { createStore, combineReducers } from 'redux';
    import { connect } from 'react-redux';
    import AuthenticatedPartialPage from './partials/home-page/authenticated';
    import AnonymousPartialPage from './partials/home-page/anonymous';
    import { loggedIntoApi, logOutOfApi } from '../actions/authentication';
    import authReducer from '../reducers/authentication'
    
    // unconnected stateless react component
    const HomePage = (props) => (
        <div>
            { !props.auth 
                ? <AnonymousPartialPage /> 
                : <AuthenticatedPartialPage /> }
        </div>
    );
    
    const mapStateToProps = (state) => {
        const store = createStore(
            combineReducers({
                auth: authReducer
            })
        );
    
        //  When the user logs in, in the Anonymous component, the local storage is set with the response
        //  of the API when the log in attempt was successful.
        const storageAuth = JSON.parse(localStorage.getItem('auth'));
        if(storageAuth !== null) {
    
            //  Clear auth state in case local storage has been cleaned and thus the user should not be logged in.
            store.dispatch(logOutOfApi());
    
            //  Make sure the auth info in local storage is contained in the state.auth object.
            store.dispatch(loggedIntoApi(...storageAuth))
        }
    
        return {
            auth: state.auth && state.auth.jwt && storageAuth === null 
                ? state.auth 
                : storageAuth
        };
    }
    
    export default connect(mapStateToProps)(HomePage);
    

    import React from 'react';
    import { connect } from 'react-redux';
    import { Link } from 'react-router-dom';
    import { loggedIntoApi } from '../../../actions/authentication';
    
    export class AnonymousPartialPage extends React.Component {
        constructor(props) {
            super(props);
        }
        onSubmit = (e) => {
            e.preventDefault();
    
            const loginData = { ... };
    
            //  This is where I thought the problem initially occurred as I 
            //  would get an error that `this.props` was undefined in the final 
            //  then` of the `fetch`. After doing this, however, the error went
            //  away and I can see that `props.dispatch is no longer undefined 
    
            //  when using it. Now though, nothing happens.
            const props = this.props;
    
            fetch('https://.../api/auth/login', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(loginData)
            })
            .then(function(response) {
                return response.json();    
            })
            .then(function(data) {
                if(data && data.jwt) {     
                    props.dispatch(loggedIntoApi(data));
                    localStorage.setItem('auth', JSON.stringify(data));
                }
                //  else show an error on screen 
            });
        };
        render() {
          return (
            <div>
                 ... onSubmit gets called successfully somewhere in here ...
            </div>
          );
        }
    }
    
    export default connect()(AnonymousPartialPage);
    

    行动:

    // LOGGED_INTO_API
    export const loggedIntoApi = (auth_token) => ({
        type: 'LOGGED_INTO_API',
        auth: auth_token
    });
    
    // LOGGED_OUT_OF_API
    export const logOutOfApi = (j) => ({
        type: 'LOG_OUT_OF_API'
    });
    

    最后是减速器:

    const authDefaultState = { };
    
    export default (state = authDefaultState, action) => {
      switch (action.type) {
        case 'LOGGED_INTO_API':
          // SOLUTION : changed this line "return action.auth;" to this:
          return { ...action.auth, time_stamp: new Date().getTime() }
        case 'LOG_OUT_OF_API':
          return { auth: authDefaultState  };
        default:
          return state;
      }
    };
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Robin Kurosawa    7 年前

    我的建议是确保您在Redux中更改的状态正在更改 根据javascript的相等运算符! . 有一个非常好的答案,另一个问题张贴抓住这个想法 here . 基本上,你不能改变一个旧的对象,并将其发送回Redux,并希望它将重新呈现,因为与旧对象的相等性检查将返回TRUE,因此Redux认为没有改变!我必须通过使用更新的值创建一个全新的对象并通过dispatch()发送它来解决这个问题。

    基本上:

    x = {
      foo:bar
    }
    
    x.foo = "baz"
    
    dispatch(thereWasAChange(x)) // doesn't update because the x_old === x returns TRUE!

    x = {
      foo:"bar"
    }
    
    y = JSON.parse(JSON.stringify(x)) // creates an entirely new object
    
    dispatch(thereWasAChange(y)) // now it should update x correctly and trigger a rerender
    
    // BE CAREFUL OF THE FOLLOWING!
    
    y = x
    
    dispatch(thereWasAChange(y)) // This WON'T work!!, both y and x reference the SAME OBJECT! and therefore will not trigger a rerender

    希望这有帮助!

    推荐文章