react + redux 无限循环

Posted

技术标签:

【中文标题】react + redux 无限循环【英文标题】:react + redux make an infinite loop 【发布时间】:2017-04-19 17:13:05 【问题描述】:

我对 react + redux 有疑问。我正在尝试让我的第一个 redux 基础应用程序运行,但我得到了一个无限循环。

我的演示应用程序只包含一个按钮,当我单击该按钮时,我想执行一个 rest api 调用。但是当我在网络浏览器中打开我的应用程序 url 时,我可以在控制台日志中看到其余 api 在无限循环中自动调用,我不知道为什么。你能帮帮我吗?

这是控制台日志:

--- start --------------------
dispatching Object  type="waiting-for-response",  waitingForResponse=true,  hasError=false
next state Object  waitingForResponse=true,  hasError=false
----- end --------------------
posting...
waiting-for-response
--- start --------------------
dispatching Object  type="waiting-for-response",  waitingForResponse=true,  hasError=false
next state Object  waitingForResponse=true,  hasError=false
----- end --------------------
...
show-cards
> --- start --------------------
dispatching Object  type="show-cards",  waitingForResponse=false,  hasError=false
Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
next state Object  waitingForResponse=false,  hasError=false
----- end ----------------------

请求-响应日志:

GET /demo/ > 200 OK
GET bootstrap.min.css > 200 OK
GET bootstrap-theme.min.css > 200 OK
GET bundle.js > 200 OK
GET time.jsontest.com > 200 OK
GET time.jsontest.com > 200 OK
GET time.jsontest.com > 200 OK
...

来源:

App.js

const logger = store => next => action => 
    console.group(action.type);
    console.log('--- start --------------------');
    console.log('dispatching', action);
    let result = next(action);
    console.log('next state', store.getState());
    console.log('--- end ----------------------');
    console.groupEnd(action.type);
    return result
;

let store = createStore(reducers, applyMiddleware(thunk, logger));

ReactDom.render(
    <Provider store=store>
        <Card/>
    </Provider>,
    document.getElementById('root')
);

Card.js

class Card extends React.Component 
    render() 
        return (
            <div>
                this.props.waitingForResponse ? <p>fetching...</p> : null
                this.props.hasError ? <p>service is not available, try it later</p> : null
                <Button onClick=this.props.getCards('param1', 'param2')>Button</Button>
            </div>
        )
    


const mapStateToProps = (state) => 
    return 
        waitingForResponse: state.waitingForResponse,
        hasError: state.hasError
    ;
;

const mapDispatchToProps = (dispatch) => 
    return 
        getCards: (param1, param2) => dispatch(performPost(param1, param2))
    ;
;

export default connect(mapStateToProps, mapDispatchToProps)(Card)

CardActionType.js

export default 
    WAITING_FOR_RESPONSE: 'waiting-for-response',
    COMMUNICATION_ERROR: 'communication-error',
    SHOW_CARDS: 'show-cards'

CardAction.js

const waitingForResponse = () => 
    return 
        type: CardActionType.WAITING_FOR_RESPONSE,
        waitingForResponse: true,
        hasError: false
    
;

const communicationError = () => 
    return 
        type: CardActionType.COMMUNICATION_ERROR,
        waitingForResponse: false,
        hasError: true
    
;

const showCard = () => 
    return 
        type: CardActionType.SHOW_CARDS,
        waitingForResponse: false,
        hasError: false
    
;

export function performPost(param1, param2) 
    return (dispatch) => 
        console.log("posting...");
        dispatch(waitingForResponse());

        axios(
            baseURL: 'http://time.jsontest.com/',
            method: 'get'
        )
            .then((response) => 
                console.log('request performed successfully');
                dispatch(showCard());
            )
            .catch((response) => 
                console.log('communication error');
                dispatch(communicationError());
            );
    

Reducer.js

const initialState = 
    waitingForResponse: false,
    hasError: false
;

export default (state = initialState, action) => 
    return Object.assign(, state, 
        waitingForResponse: action.waitingForResponse,
        hasError: action.hasError
    );

【问题讨论】:

【参考方案1】:

在 CardAction 的渲染方法中,您不向 onClick 处理程序提供回调函数,而是执行操作创建器。你应该在一个函数中调用动作创建者,所以你应该把它写成一个粗箭头函数。

发生的情况是每次渲染都会调用 action-creator,并且渲染函数会不断被调用,因为您不断更新 redux-store。

class Card extends React.Component 
    render() 
        return (
            <div>
                this.props.waitingForResponse ? <p>fetching...</p> : null
                this.props.hasError ? <p>service is not available, try it later</p> : null
                <Button onClick=() => this.props.getCards('param1', 'param2')>Button</Button>
            </div>
        )
    

为了澄清,使用:

&lt;Button onClick=() =&gt; this.props.getCards('param1', 'param2')&gt;Button&lt;/Button&gt;

代替:

&lt;Button onClick=this.props.getCards('param1', 'param2')&gt;Button&lt;/Button&gt;

【讨论】:

很高兴为您提供帮助:)

以上是关于react + redux 无限循环的主要内容,如果未能解决你的问题,请参考以下文章

使用 React、Jest、Redux 和 Thunk 进行无限循环测试

使用带有 JWT 令牌的 Axios 对 Redux saga 产生调用的无限循环

为啥我在 React JS 中的代码会进入满足这两个条件的无限循环?

我有一个错误:重新渲染太多。 React 限制渲染次数以防止无限循环

错误:重新渲染过多。 React 限制了渲染的数量以防止无限循环。即使使用箭头函数

Apollo 客户端和 Redux 设置导致无限渲染循环