在现有状态转换错误期间无法更新

时间:2018-11-01 06:02:46

标签: reactjs redux react-redux react-router-v4

编辑:我已经解决了我的问题,它现在对我有用-还编辑了我的代码以反映新的更改。

我遇到此错误,我不确定导致此错误的原因。

我无法显示代码,因为它是公司的材料,所以我会尽力描述它:

App.js:

`class App extends React.Component {
    constructor(props) {
        super(props);
    }

    render () {
        return (
            <div>
                <Header />
                <RouteList />
                <Footer />
            </div>
        )
    }
}`

我的<RouteList />是一个无状态函数,它返回Web应用程序的所有路由。

Header.js:

class Header extends React.Component {
    constructor (props) {
        super(props);
        this.changeHeader = this.changeHeader.bind(this);
    }

    changeHeader(headerType) {
        this.props.actions.changeHeader(headerType)
    }

    GetHeader() {
        // if-else statement which will return a different sub header class
        const HeaderType = this.props.renderHeader.headerType
        if (headerType == 'abc') {
            <aHeader changeHeader={this.changeHeader} />
        } [...] {
            // Final else block return something
        }
    }

    render () {
        return (
            <div>{this.GetHeader()}</div>
        )
    }
}

function mapStateToProps(state, ownProps) {
    return { renderHeader: state.renderHeader};
}

function mapDispatchToProps(dispatch) {
    return { actions: bindActionCreators(headerActions, dispatch) };
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Header));

this.props.action.changeHeader(headerType)是一个if-else语句,根据headerType的值,它将触发不同的操作。

state.renderHeader在我的rootReducer中声明。

我将changerHeader()传递到无状态的单个header.js(即aHeader.js,bHeader.js ...)。单击导航链接时,它将调用该方法,并将页面路由到另一个UI。这就是我将方法嵌入到navlink中的方式:onClick={changeHeader(input')}

rootReducer.js

const rootReducer = combineReducers({renderHeader});
export default rootReducer;

renderHeader是renderHeaderReducer。

headerAction.js

export function changeHeader(headerType) {
    if (headerType == "abc") {
        return {type: type, headerType: "abc"}
    } [...] {
        // something default
    }
}

renderHeaderReducer.js

export default function renderHeaderReducer(state = initialState, action) {
switch(action.type) {
    case "abc":
        return (Object.assign({}, ...state, {headerType: action.headerType}));
    [...];
    default:
        return state;
}

}

这时,单击链接时,Web浏览器应刷新,将标题保留在原位置,但修改零件。但是我的网站陷入无限循环,错误是:

错误:在现有状态转换期间(例如在渲染或其他组件的构造函数中)无法更新。渲染方法应该纯粹是道具和状态的函数;构造函数的副作用是反模式,但可以将其移至componentWillMount。

当我做一个console.log来查看发生了什么时,似乎遍历了我定义的所有呈现Header.js的选项

事实证明,主要的问题是我调用onClick方法时出现的。困扰我代码的无限循环是onClick函数触发的结果,甚至没有被点击。

原文:onClick={this.changeHeader('abc')} 新增:onClick={() => changeHeader('abc')}

请参阅此post以获得解释。

谢谢。

2 个答案:

答案 0 :(得分:2)

一些伪代码的时间:)

据我了解,您有一个Header Component,它连接到rootReducer组件,该组件包含您所在的Router Link的标头。

我的应用程序中有一些类似的代码,其中我们使用各个组件的分派操作来更新rootReducer标头。标头仅使用redux监听更​​新,然后重新呈现。

class Header extends React.Component {
     // render the header 
     render() {...}
 }
 const mapStateToProps = (state) => {
     return {
        header: state.rootReducer.header
     }
 }
 export default withRouter(connect(mapStateToProps, {})(Header));

组件

 class MySpecialRouteComponent extends React.Component {
     componentDidMount() {
         this.props.changeHeader("Special Component")
     }
     render() {...}
 }
 const mapStateToProps = (state) => {
     return {
       ...whatever 
     }
 }
 export default withRouter(connect(mapStateToProps, {changeHeader})(MySpecialRouteComponent));

您不应在React中让render做setState!

答案 1 :(得分:1)

我将展示如何设置一切以处理这种情况。

redux / header-actions.js (从您的组件中调用这些动作创建者):

export const changeHeader = (headerType) => {
    return {
        type: 'CHANGE_HEADER',
        payload: {
            headerType: headerType
        }
    }
}

redux / header-reducers.js (注意:当您调用该操作时,将对其进行处理):

const INITIAL_STATE = {
    headerType: 'header-a'
};

export default function(state = INITIAL_STATE, action) {
    switch (action.type) {
        case 'CHANGE_HEADER':
            return changeHeader(state, action.payload);
        default:
            return state;
    }
}

const changeHeader = (state, payload) => {
    // this is where your app will update the state, to indicate
    // which header should be displayed:
    return {
        ...state,
        headerType: payload.headerType
    }
}

redux / index.js

import headerReducers from './reducers/header-reducers';
import { combineReducers } from 'redux';

const allReducers = combineReducers({
    header: headerReducers
});

export default allReducers;

现在,您可以像这样设置 header.js 组件:

import { changeHeader } from '../redux/header-actions';

class Header extends Component {

    render() {
        return (
            <div>{this.renderHeader()}</div>
        );
    }

    renderHeader() {
        if (this.props.headerType === 'header-a')
            return <aHeader changeHeader={this.props.changeHeader} />
        else
            return <bHeader changeHeader={this.props.changeHeader} />;
    }

}

function mapStateToProps(store, ownProps) {
    return {
        headerType: store.header.headerType
    };
}

function mapDispatchToProps(dispatch) {
    return bindActionCreators({
        changeHeader: changeHeader
    },
    dispatch);
}

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Header));

然后输入例如 aHeader.js

class aHeader {

    constructor() {
        super();
        this.changeHeader = this.changeHeader.bind(this);
    }

    render() {
        return <div onClick={this.changeHeader}>header a</div>;
    }

    changeHeader() {
        this.props.changeHeader('header-b'); // call the action creator here
    }
}