React-Redux:按钮单击时的动作调度不起作用

IT技术 javascript reactjs redux react-redux
2021-05-25 01:29:55

单击按钮时,我的操作没有被调度。下面是所有文件,即动作、reducer、root reducer、configSTore、Index 和 Component。

请帮助我为什么我的操作没有在按钮点击时被发送

动作.js

import axios from 'axios';

const requestURL='JSONUrl';
let responseData = '';

export function fetchRequests() {
    axios.get(requestURL)
    .then((res) => {
        responseData = res;
    });
    return responseData;
}

export const fetchDataAction = () => {
    return {
        type: 'FETCH_DATA',
        data: fetchRequests()
    };
}

export function fetchDataSuccessAction(err) {
    return {
        type: 'FETCH_DATA_SUCCESS',
        err
    };
}

export function fetchDataErrorAction(err) {
    return {
        type: 'FETCH_DATA_ERROR',
        err
    };
}

减速器.js


export function fetchDataReducer(state = [], action) {
        switch(action.type) {
            case 'FETCH_DATA':
                return action.data;
            default: return state;
        }
}

export function fetchDataSuccessReducer(state = [], action) {
    switch(action.type) {
        case 'FETCH_DATA_SUCCESS':
            return action.err;
        default: return state;
    }
}

export function fetchDataErrorReducer(state = [], action) {
    switch(action.type) {
        case 'FETCH_DATA_ERROR':
            return action.err;
        default: return state;
    }
}

RootReducer

import {combineReducers} from 'redux';
import { fetchDataAction, fetchDataSuccessAction, fetchDataErrorAction}
from '../actions/fetchData';

export default combineReducers({
    fetchDataAction,
    fetchDataSuccessAction,
    fetchDataErrorAction
});

configStore.js

import { createStore, applyMiddleware } from "redux";
import rootReducer from "../reducers/rootReducer";
import thunk from 'redux-thunk';

export default function configureStore() {
    const enhance = applyMiddleware(thunk);
 
    return createStore(
        rootReducer,        
        enhance
    );
}

索引.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

import reportWebVitals from './reportWebVitals';
import Header from './App';
import configureStore from './store/configureSTore';
import {CounterApp} from './counter';
import { Provider } from 'react-redux';

ReactDOM.render(
    <Provider store={configureStore()}>
      <Header favcol="yellow"/>   
      <CounterApp /> 
    </Provider>,
  document.getElementById('root')
);

reportWebVitals();

我的组件文件

import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';

 export class CounterApp extends React.Component {
    constructor(props) {
        super(props);
    }
    btnClick = () => {
        return this.props.fetchDataAction;        
    }
    render() {   
          
    return (        
        <div className="App">
            <h1>Hello</h1>                                       
            <div>
                <h1>Fetch Data click below</h1>
                <button onClick={() => this.props.fetchDataAction}>
                Fetch Data
                </button>
                {this.props.datafetchedFromApi}            
            </div>
        </div>
        )
    }
    
}
const mapStateToProps = state => ({    
    datafetchedFromApi: state.data
    
});

const mapDispatchToProps = (dispatch) => ({
    fetchDataAction: () => dispatch(fetchDataAction())  
});


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

单击按钮时,我的操作没有被调度。下面是所有文件,即动作、reducer、root reducer、configSTore、Index 和 Component。

请帮助我为什么我的操作没有在按钮点击时被发送

4个回答

答案太长了,所以第一部分是如果你想完全理解为什么事情会向南。如果你只是想解决你的问题以便你最终可以去尿尿,那么第二部分是给你的:)。

第一部分(基本上什么是 JavaScript 中的异步编程,所以任何关于什么是 JS 中的异步任务的问题都可以参考这个答案。)

好的,这里检测到几个问题。正如其他人指出的那样,确保所有导入路径都是正确的。现在假设它们都是正确的,这就是您需要做的来解决您的问题。

首先让我们看一下组件文件的顶部:

import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';
...

然后是您调用 fetchDataAction 的块:

...
<button onClick={() => this.props.fetchDataAction}>
   Fetch Data
</button>
...

在这里你所做的是this.props.fetchDataAction,我没有看到你将 fetchDataAction 作为props传递给这个组件,所以它很可能是未定义的,这就是为什么你会收到错误,TypeError: this.props.fetchDataAction is not a function因为undefined不是函数。这是我注意到的第一个错误。

现在,继续第二个。我要从这个开始

redux 中的调度操作是同步的。 因此,您不能执行以下操作:

export default function SomeComponent(props) {
  const fetchAction = () => {
     let payload;
     //wait for 5 seconds for the async task(the setTimeout below is an async task) to populate the payload with data.
     setTimeout(() => payload = "This is my data", 5000); 
     //then return the action object
     return {
       type: 'Data',
       payload,
     };
   }
   const handleClick = () => {
       dispatch(fetchAction());
   }
   return (<>
    <Button onClick={handleClick} />
  </>);
}

以上不会抛出任何错误,但肯定不会做我想要它做的事情。以上将分派以下动作对象:

{
  type: 'Data',
  payload: undefined
}

这当然不是我想要的有效载荷。

而这正是你正在做的。看看你的fetchDataActionfetchRequests函数:

...
let responseData = '';

export function fetchRequests() {
    axios.get(requestURL)
    .then((res) => {
        responseData = res;
    });
    return responseData;
}

export const fetchDataAction = () => {
    return {
        type: 'FETCH_DATA',
        data: fetchRequests()
    };
}
...

现在我将与上面给出的示例进行比较:

  • 这里你responseData的类似于我的payload
  • 你的fetchRequests功能类似于我的setTimeout

看起来很熟悉?我确定现在确实如此。关于为什么它不起作用的简单答案是您正在执行异步任务,在您的情况下,您正在使用 axios.get(requestUrl) 发出网络请求...

网络请求是异步的(现在,如果您不知道什么是异步,请查看https://javascript.info/callbacks,它可以让您了解它们是什么。还可以查看 TheNetNin​​ja 的视频https:// www.youtube.com/watch?v=ZcQyJ-gxke0),简单来说,\network 请求需要一些时间才能完成(就像 setTimeout 一样)。

因此 axios.get 请求需要一些时间才能从服务器获取响应。现在其他任务(在它下面)不会等待该请求完成,而是 js 将立即执行这些任务而无需等待响应。

我知道这个答案太长了。但我想让你明白,因为相信我,我以前也犯过同样的错误:)。

所以在你的fetchRequests函数中:

export function fetchRequests() {
    axios.get(requestURL) --- (1)
    .then((res) => {
        responseData = res; --- (2)
    });
    return responseData; --- (3)
}

在第 1 行中,您启动了一个异步任务。记住then内的函数只会在一段时间后执行。所以 responseData 仍然是未定义的。代替第 (2) 行,第 (3) 行将首先执行,因为正如我之前告诉您的,js 不会等待来自服务器的响应(技术措辞是“线程不会被网络请求阻塞”) .) 所以基本上你从这个函数返回 undefined 。

另请参阅 JavaBrains 的此视频。他使用了一个很好的类比来理解 js 中的异步任务,您可能还会了解事件循环是什么以及 javascript 的单线程性。 https://www.youtube.com/watch?v=EI7sN1dDwcY

现在第二部分(我真的很想去小便):替换(我已经指出了我所做的更改)

您的组件文件与此。

import React, { useState } from 'react';
import { fetchDataAction, fetchRequests } from './actions/fetchData';
import { connect } from 'react-redux';

export class CounterApp extends React.Component {
  constructor(props) {
      super(props);
  }
  btnClick = () => {
     return this.props.fetchDataAction;        
  }
    render() {       
        return (        
            <div className="App">
                <h1>Hello</h1>                                       
                <div>
                    <h1>Fetch Data click below</h1>
                    <button onClick={() => fetchDataAction()}> //this is the only change here
                        Fetch Data
                    </button>
                    {this.props.datafetchedFromApi}            
                </div>
            </div>
        )
    } 
}
const mapStateToProps = state => ({    
    datafetchedFromApi: state.data  
});

const mapDispatchToProps = (dispatch) => ({
    fetchDataAction: () => dispatch(fetchDataAction())  
});

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

然后在您的action.js文件中:

import axios from 'axios';

const requestURL='JSONUrl';
let responseData = '';

export function fetchRequests() { 
    return axios.get(requestURL) //change is here
    //removed return responseData and the 'then' block
}

export const fetchDataAction = () => { 
    return dispatch => {                        //almost whole of this function is changed and that's it
    fetchRequests().then((res) => {
       responseData = res;
       dispatch({
            type: 'FETCH_DATA',
            data: responseData
       })
    });
  };
}

export function fetchDataSuccessAction(err) {
    return {
        type: 'FETCH_DATA_SUCCESS',
        err
    };
}

export function fetchDataErrorAction(err) {
    return {
        type: 'FETCH_DATA_ERROR',
        err
    };
}

现在它应该可以工作了。如果没有,请告诉我更多。请记住,此答案假设您已将所有函数正确导入到文件中。如果这不能回答您的问题,我将进行编辑。

所以答案是使用“thunk”——一个用于 redux 的官方“异步函数中间件”。

另请参阅此内容以了解有关处理“异步操作”以及使用 redux thunk 的更多信息:https : //redux.js.org/tutorials/fundamentals/part-6-async-logic https://www.npmjs.com/package /redux-thunk

试试这个

<button onClick={() => this.props.fetchDataAction()}>

此外,如果您需要从组件中发送 url,您可以这样做

    <button onClick={() => this.props.fetchDataAction(url)}>


    const mapDispatchToProps = (dispatch) => {
    return {
    fetchDataAction: (url) => dispatch(fetchRequests(url))
     };
     };

在 Action.js 中

   export function fetchRequests(url) {
    axios.get(url)
    .then((res) => {
    responseData = res;
    });
   return responseData;
   }
<button onClick={() => this.props.fetchDataAction()}> 

<button onClick={() => this.props.fetchDataAction}> 在这里,您试图单独返回函数定义,而不是调用 fetchDataAction onclick 使用 onClick={() => this.props.fetchDataAction()}或为 onclick 传递单独的处理程序作为良好做法。

对于您提到的另一个问题 TypeError: this.props.fetchDataAction is not a function 是因为导入 fetchRequests 时使用了大括号

删除大括号

import fetchRequests from "./actions/fetchData";

这应该可以解决您的问题