Rest 反应+;重复生成一个无限循环

Rest 反应+;重复生成一个无限循环,rest,api,reactjs,redux,react-redux,Rest,Api,Reactjs,Redux,React Redux,我对react+redux有问题。我试图让我的第一个redux基础应用程序工作,但我得到了一个无限循环 我的演示应用程序只包含一个按钮,当我点击该按钮时,我想执行RESTAPI调用。但是,当我在web浏览器中打开我的应用程序url时,我可以在控制台日志中看到RESTAPI是在无限循环中自动调用的,我不知道为什么。你能帮帮我吗 这是控制台日志: --- start -------------------- dispatching Object { type="waiting-for-respons

我对react+redux有问题。我试图让我的第一个redux基础应用程序工作,但我得到了一个无限循环

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

这是控制台日志:

--- 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
...
请求-响应日志:

--- 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')
);
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)
export default {
    WAITING_FOR_RESPONSE: 'waiting-for-response',
    COMMUNICATION_ERROR: 'communication-error',
    SHOW_CARDS: 'show-cards'
}
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());
            });
    }
}
const initialState = {
    waitingForResponse: false,
    hasError: false
};

export default (state = initialState, action) => {
    return Object.assign({}, state, {
        waitingForResponse: action.waitingForResponse,
        hasError: action.hasError
    });
}
CardAction.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')
);
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)
export default {
    WAITING_FOR_RESPONSE: 'waiting-for-response',
    COMMUNICATION_ERROR: 'communication-error',
    SHOW_CARDS: 'show-cards'
}
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());
            });
    }
}
const initialState = {
    waitingForResponse: false,
    hasError: false
};

export default (state = initialState, action) => {
    return Object.assign({}, state, {
        waitingForResponse: action.waitingForResponse,
        hasError: action.hasError
    });
}
Reducer.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')
);
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)
export default {
    WAITING_FOR_RESPONSE: 'waiting-for-response',
    COMMUNICATION_ERROR: 'communication-error',
    SHOW_CARDS: 'show-cards'
}
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());
            });
    }
}
const initialState = {
    waitingForResponse: false,
    hasError: false
};

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

在CardAction的呈现方法中,您不向onClick处理程序提供回调函数,而是执行action creator。您应该在函数中调用action creator,因此应该将其编写为fat arrow函数

发生的情况是,在每次渲染时都会调用action creator,并且由于您不断更新redux存储,因此渲染函数会不断被调用

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>
        )
    }
}
类卡扩展React.Component{
render(){
返回(
{this.props.waitingForResponse?正在获取…

:null} {this.props.hasError?服务不可用,请稍后再试

:null} 这个.props.getCards('param1','param2')}>按钮 ) } }
因此,要澄清,请使用:

this.props.getCards('param1','param2')}>按钮

而不是:


按钮

很乐意帮助:)