【问题标题】:Redux - Unable to use dispatch to call action inside of axios responseRedux - 无法使用调度在 axios 响应中调用操作
【发布时间】:2020-05-10 12:36:12
【问题描述】:

我是 react 和 redux 的新手,这是我第一次尝试使用 redux 操作来调用 API,它会返回一个产品列表,然后我可以将其添加到 redux 商店以供我在任何组件中使用。到目前为止,API 调用正在运行,并在我在 then 响应中添加 console.log 时返回产品列表,但是当我使用 dispatch 调用设置类型的下一个操作时,我收到错误“未处理的拒绝(TypeError) :调度不是一个函数”。

这是我的 Fetch.js 文件:

import axios from "axios";
import * as React from "react";

export function loadProducts() {
    return dispatch => {
        return axios.get(getApiHost() + 'rest/productComposite/loadProductsWithImages/' + getId() + '/ENV_ID').then((response) => {
           dispatch(getProducts(response.data.productDtos));
        })
    }
}

export function getProducts(productDtos) {
    return {
        type: 'product',
        productDtos: productDtos
    }
}

function getId() {
    return params().get('id');
}

function getEnv() {
    let env = params().get('env');
    if (!env) return 'prod';
    return env;
}

function getApiHost() {

}

function params() {
    return new URLSearchParams(window.location.search);
}


还有我的 reducer.js 文件:

const initialState = {
    loaded: 'false',
    productDtos: []
}

const productReducer = (state = initialState, action) => {

    switch (action.type) {
        case 'product':
            return {
                ...state,
                loaded: 'true',
                productDtos: action.productDtos
            }
        default:
            return {
                ...state,
                loaded: 'false',
                productDtos: action.productDtos
            };
    }
}

export default productReducer;

和我的 index.js 文件: (这个文件中有很多乱七八糟的代码,这就是我试图将项目转换为 redux 的原因)

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import * as serviceWorker from './serviceWorker';
import {createStore, compose, applyMiddleware } from 'redux';
import allReducers from './components/reducers'
import {Provider} from 'react-redux';
import thunk from "redux-thunk";

const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
    allReducers,
    composeEnhancer(applyMiddleware(thunk)),
);

ReactDOM.render(
  <React.StrictMode>
      <Provider store = {store}>
          <App/>
      </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

serviceWorker.unregister();

还有我的 app.js 文件:

import React from 'react';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import PageHero from './PageHero';
import Products from './Products';
import ProductDetail from "./ProductDetail";
import Cart from "./Cart";
import ErrorBoundary from "./ErrorBoundary";
import PrivacyPolicy from "./PrivacyPolicy";
import LicenceAgreement from "./LicenceAgreement";
import {loadProducts} from "./Fetch";
import {connect} from "react-redux";

class App extends React.Component {

    constructor(props) {
        super(props);
        this.cartProductsRef = React.createRef();
        this.state = {
            loadedShopConfig: false,
            loadedLogo: false,
            productView: false,
            products: null,
            logoUrl: null,
            lAView: false,
            pPView: false
        };
        this.onChange = this.onChange.bind(this)
        this.changeBack = this.changeBack.bind(this)
        this.addToCart = this.addToCart.bind(this)
        this.lAViewChange = this.lAViewChange.bind(this)
        this.pPViewChange = this.pPViewChange.bind(this)


    }

    params() {
        return new URLSearchParams(window.location.search);
    }

    getId() {
        return this.params().get('id');
    }

    getEnv() {
        let env = this.params().get('env');
        if (!env) return 'prod';
        return env;
    }

    getApiHost() {

    }

    componentDidCatch(error, info) {
        // Display fallback UI
        this.setState({hasError: true});
        // You can also log the error to an error reporting service
        console.log('error', error);
        console.log('info', info);
    }

    changeBack() {
        this.setState({
            productView: false,
            lAView: false,
            pPView: false
        });
    }

    onChange(event) {
        this.setState({productView: true});
        this.setState({selectedProduct: event})
    }

    addToCart(product, quantity) {
        console.log('cartProductsRef', this.cartProductsRef);
        if (this.cartProductsRef.current) {
            this.cartProductsRef.current.addToCart(product.entityInstanceId.id, quantity, product);
        }
        this.setState({})
    }

    lAViewChange() {
        this.setState({lAView: true});
    }

    pPViewChange() {
        this.setState({pPView: true});
    }


 loadShopDetails() {
        this.setState({...this.state, isFetching: true});
        fetch(this.getApiHost() + 'rest/shopComposite/' + this.getId() + '/ENV_ID')
            .then((response) => response.json())
            .then((responseJson) => {
                console.log('Shop Details Function Results ', responseJson);
                this.setState({
                    shopConfig: responseJson.shopConfig,
                    logoUrl: responseJson.logoUrl,
                    currencyCode: responseJson.currencyCode,
                    website: responseJson.website,
                    twitter: responseJson.twitter,
                    facebook: responseJson.facebook,
                    instagram: responseJson.instagram,
                    linkedIn: responseJson.linkedIn,
                    youTube: responseJson.youTube,
                    loadedShopConfig: true,
                    loadedLogo: true
                });
            })
        this.setState({...this.state, isFetching: false});
    }

    componentDidMount() {
        this.loadShopDetails();
        this.props.dispatch(loadProducts());

    }

    render() {
        let displayProduct;
        const {lAView} = this.state;
        const {pPView} = this.state;
        const {productView} = this.state;
        const {shopConfig} = this.state;
        const {logoUrl} = this.state;
        const {selectedProduct} = this.state;
        if (productView && !lAView && !pPView) {
            displayProduct = <ProductDetail
                product={selectedProduct}
                addToCart={this.addToCart}
            />;
        } else if (!lAView && !pPView) {
            displayProduct =
                    <Products
                        shopConfig={this.state.shopConfig}
                        productSelectedHandler={this.onChange}
                    />;

        }

        return (

            <div id="page">

                <ErrorBoundary>


                    <p>{this.state.productView}</p>

                    <Header
                        logoUrl={this.state.logoUrl}
                        itemsInCart={this.state.itemsInCart}
                        changeBack={this.changeBack}
                        currencyCode={this.state.currencyCode}
                    />


                    {!productView && !lAView && !pPView && this.state.loadedShopConfig ?
                        <PageHero shopConfig={this.state.shopConfig}/> : null}

                    {displayProduct}

                    <Cart id={this.getId()}
                          apiHost={this.getApiHost()}
                          ref={this.cartProductsRef}
                          currencyCode={this.state.currencyCode}
                    />

                    {lAView ? <LicenceAgreement
                        shopConfig={this.state.shopConfig}
                    /> : null }

                    {pPView ? <PrivacyPolicy
                        shopConfig={this.state.shopConfig}
                    /> : null }


                    {this.state.loadedLogo ? <Footer
                        logoUrl={this.state.logoUrl}
                        lAChange={this.lAViewChange}
                        pPChange={this.pPViewChange}
                        twitter={this.state.twitter}
                        facebook={this.state.facebook}
                        instagram={this.state.instagram}
                        linkedIn={this.state.linkedIn}
                        youTube={this.state.youTube}
                        website={this.state.website}

                    /> : null}

                </ErrorBoundary>


            </div>
        );
    }
}

function mapDispatchToProps() {
    return loadProducts()
}

export default connect(mapDispatchToProps)(App);

提前感谢任何帮助我的人,这可能是我做错的事情的快速修复,尽管我已经阅读了很多文章并观看了很多视频并且找不到直接的问题。

【问题讨论】:

  • 你如何调度loadProducts action?
  • 我已经附上了上面的app.js文件

标签: javascript reactjs redux react-redux axios


【解决方案1】:

这是您在连接组件中调度操作的方式。请注意,mapStateToProps 是您传递给 connect 函数的第一个参数,即使它返回一个空对象:

import { connect } from 'react-redux'
import { loadProducts } from './path/to/actions'

class App extends React.Component {
  componentDidMount() {
    this.props.loadProducts();
  }

  render() { ... }
}

const mapStateToProps = () => ({});
const mapDispatchToProps = { loadProducts };

export default connect(mapStateToProps, mapDispatchToProps)(App);

【讨论】:

  • 非常感谢,为我节省了很多时间。谢谢!
【解决方案2】:

可能是你没有连接 loadProducts

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-30
    • 2018-09-07
    • 2018-12-10
    • 2019-12-29
    • 2019-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多