2016-12-05 159 views
1

我有一個與react + redux有關的問題。我試圖讓我的第一個基礎應用程序工作,但我得到了一個無限循環。react + redux使無限循環

我的演示應用程序僅包含一個按鈕,當我點擊該按鈕時,我想執行其他api調用。但是,當我在Web瀏覽器中打開我的應用程序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 
    }); 
} 

回答

0

在渲染CardAction的方法,你不給的onClick處理程序提供了一個回調函數,而不是你執行行動的創建者。你應該在一個函數內調用動作創建器,所以你應該把它寫成一個胖箭頭函數。

會發生什麼事是在每個渲染器上調用動作創建器,並且渲染函數一直在調用,因爲您不斷更新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> 
     ) 
    } 
} 

所以要澄清,使用:的

<Button onClick={() => this.props.getCards('param1', 'param2')}>Button</Button>

代替:

<Button onClick={this.props.getCards('param1', 'param2')}>Button</Button>

+0

那是如此之快;)感謝你的幫助。 – zappee

+0

很高興幫助:) – Alexander