组件没有重新渲染,调用减速器和道具后没有更新?

人气:42 发布:2023-01-03 标签: javascript reactjs redux react-redux redux-saga

问题描述

我正在尝试从股票API获取一些股票数据。 我可以使用正常的反应钩子来获取它,但在使用Redux和Redux Saga来获取它时,我面临着问题。 在第一次渲染中,它不会更新redux存储。 它更新第二个渲染中的复制存储。 但即使更新了Redux存储区,我的组件也不会获得更新状态??

有人能帮忙吗?

这是我的组件:

import React, { useState,useEffect } from 'react'
import { connect } from "react-redux";
import { Link } from 'react-router-dom'
function Dashboard(props) {

    useEffect(()=>{
            console.log(props)
            props.getStockData()
    },[])

    useEffect(()=>{
        props.getStockData()
        console.log(props)
    },[props.stocks.length])
  
    return (
        <React.Fragment>
                {props.stocks.length ? 

                    <div> 
                    <h1>hello</h1>
                    </div>
                
                    :   <button class=" p-4 m-4 spinner"></button>
                
                }
        </React.Fragment>
    ) 
   
}
const mapStateToProps = state => {
    return {
      stocks: state
    };
  };
  
const mapDispachToProps = dispatch => {
    return {
      getStockData: () => dispatch({ type: "FETCH_STOCKS_ASYNC" }),
    };
};
export default connect(mapStateToProps,mapDispachToProps)(Dashboard)

这是我的减速器文件:

import axios from 'axios'
import swal from 'sweetalert'
const initialState = {
    stocks:[],
};
const reducer = (state = initialState, action) => {
    const newState = { ...state };
  
    switch (action.type) {
      case 'FETCH_STOCKS_ASYNC':
        console.log('reducer called')
        const getLatestPrice = async()=>{
            await axios.get(`http://api.marketstack.com/v1/eod/latest?access_key=8c21347ee7c5907b59d3cf0c8712e587&symbols=TCS.XBOM`)
            .then(res=>{
                console.log(res.data)
                newState.stocks = res.data
            })
            .catch(err=>{
                console.log(err)
            })
        }
        getLatestPrice();
        
        break;
    }
    return newState;
};
  
export default reducer;

这是我的Redux Saga文件:

import { delay } from "redux-saga/effects";
import { takeLatest, takeEvery, put } from "redux-saga/effects";

function* fetchStockData() {
  yield delay(4000);
  yield put({ type: "FETCH_STOCKS_ASYNC" });
}

export function* watchfetchStockData() {
  yield takeLatest("FETCH_STOCKS_ASYNC", fetchStockData);
}

这是我的存储文件:

import { createStore,applyMiddleware,compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import { watchfetchStockData } from './sagas'
import reducers from './reducers'


const sagaMiddleware = createSagaMiddleware()
const store = createStore(
        reducers,
        compose(
                applyMiddleware(sagaMiddleware),
               window.devToolsExtension && window.devToolsExtension()
            ),
       
)

console.log(store.getState())

// only run those sagas whose actions require continuous calling.
//sagaMiddleware.run(watchfetchStockData);


export default store;

这是我的索引文件,它将提供程序连接到所有组件:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './assets/main.css'
import App from './App';
import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom'
import store from './store'
import * as serviceWorker from './serviceWorker';

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

serviceWorker.unregister();

推荐答案

您误解了这些部分在这里应该如何组合在一起。我强烈建议您阅读redux best practices,了解更多关于减速机做什么和不做什么的知识。Redux Reducer不应执行任何操作。它仅获取当前状态,并根据操作对象中的数据返回下一个状态。

幸运的是,您已经在使用redux-saga,它旨在处理API调用等副作用。提取需要在您的佐贺中执行,而不是在减速器中执行。

API调用通常涉及调度三个操作:启动、成功和失败。从您的组件中,您只需发送";FETCH_STOCKS_START&Quot;操作。Saga";通过takeLatest获取此操作,并使用它来执行具有call效果的FETCH。当获取完成时,SAGA使用put分派两个结果操作之一。它发送带有包含股票数组的属性payload的";FETCH_STOCKS_SUCCESS&Quot;类型,或带有包含错误的属性error的&Quot;FETCH_STOCKS_ERROR&Quot;类型。

function* fetchStockData() {
  yield delay(4000);
  try {
    const res = yield call( axios.get, `http://api.marketstack.com/v1/eod/latest?access_key=8c21347ee7c5907b59d3cf0c8712e587&symbols=TCS.XBOM`);
    yield put({ type: "FETCH_STOCKS_SUCCESS", payload: res.data });
  }
  catch (error) {
    yield put({ type: "FETCH_STOCKS_ERROR", error });
  }
}

function* watchfetchStockData() {
  yield takeLatest("FETCH_STOCKS_START", fetchStockData);
}

相关传奇文档链接:Error Handling和Dispatching Actions

我已经向状态添加了isLoading属性,当true时,您可以选择该属性以显示不同的UI。我们将使用所有三个操作更新此属性。

const initialState = {
  stocks: [],
  isLoading: false
};

您的减少器仅用于根据这些操作更新状态中的原始数据。

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "FETCH_STOCKS_START":
      return {
        ...state,
        isLoading: true
      };
    case "FETCH_STOCKS_ERROR":
      console.error(action.error); // only temporary since you aren't doing anything else with it
      return {
        ...state,
        isLoading: false
      };
    case "FETCH_STOCKS_SUCCESS":
      return {
        ...state,
        stocks: action.payload,
        isLoading: false
      };
    default:
      return state;
  }
};

14