在HOC内部的分派上重新渲染React-Redux不起作用

时间:2018-09-09 16:21:25

标签: react-redux

我忙于一些概念验证,基本上要求在用户尚未登录时使主页成为登录屏幕,然后在状态更改时显示具有相关内容的组件。成功认证后。

我必须事先声明我是个新手,可以做出反应并进行还原,并且正忙于完成教程以提高自己的技能。但是,本教程有点基础,因为它不需要处理与服务器的连接即可完成工作。

我的第一个问题是在then的最后一个fetch的上下文中获得道具,因为我遇到了this.props.dispatch未定义的错误。我使用了旧的javascript技巧,如果在最后的console.log中放了then,则可以看到它不再是未定义的,而是实际上按预期的功能。

对我来说,现在的问题是,调用dispatch时什么也没发生。但是,如果我手动刷新页面,它将填充AuthenticatedPartialPage,因为localstorage已填充。

我的理解是,在调用dispatch时,将重新评估条件语句,并显示AuthenticatedPartialPage

感觉dispatch没有将更改传达回父组件,因此似乎什么都没发生。这是正确的吗?如果是这样,我将如何连接那段代码?

主页HOC:

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);

其中匿名LOC为:

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 个答案:

答案 0 :(得分:1)

我的建议是确保您在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

希望这会有所帮助!