Не удается обновить во время существующей ошибки перехода состояния - PullRequest
0 голосов
/ 01 ноября 2018

РЕДАКТИРОВАТЬ: я решил свою проблему, и она работает для меня сейчас - также отредактировал мой код, чтобы отразить новые изменения.

Я получаю эту ошибку, и я не уверен, что является причиной этой ошибки.

Я не могу показать код, поскольку это материал компании, поэтому я постараюсь описать его:

App.js:

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

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

My <RouteList /> - это функция без сохранения состояния, которая возвращает все маршруты для веб-приложения.

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 ...). Если щелкнуть навигационную ссылку, она вызовет метод, а также направит страницу к другому пользовательскому интерфейсу. Вот как я встраиваю метод в 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;
}

}

В этот момент при нажатии на ссылку веб-браузер должен обновиться, оставив заголовок на месте, но изменив часть. Однако мой сайт заходит в бесконечный цикл, и ошибка:

Ошибка: невозможно обновить во время существующего перехода состояния (например, в рамках визуализации или конструктора другого компонента). Методы рендеринга должны быть чистой функцией реквизита и состояния; побочные эффекты конструктора - это не шаблон, но их можно переместить в componentWillMount.

Когда я делал console.log, чтобы увидеть, что происходит, он, кажется, перебирает все различные опции, которые я определил, которые будут отображать Header.js

Оказывается, основная проблема была в том, что я вызвал свой метод onClick. Бесконечный цикл, в котором произошел мой код, был результатом срабатывания функции onClick даже без нажатия.

Оригинал: onClick={this.changeHeader('abc')} Новый: onClick={() => changeHeader('abc')}

Обратитесь к этому сообщению для объяснения.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Я просто покажу, как бы я все настроил, чтобы справиться с этой ситуацией.

redux / header-actions.js (вызвать этих создателей действий из ваших компонентов):

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

redux / header-redurs.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
    }
}

перевождь / 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
    }
}
0 голосов
/ 01 ноября 2018

время для некоторого псевдокода:)

Насколько я понимаю, у вас есть компонент Header, который подключен к компоненту rootReducer, который содержит заголовок, для которого вы используете Router Link.

У меня есть похожий код в моем приложении, где мы используем действие отправки отдельных компонентов для обновления заголовка rootReducer. Заголовок просто прослушивает обновления с использованием приставки и выполняет повторную визуализацию.

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

Вы не должны заставлять рендер делать setState в React!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...