组件没有重新渲染,调用减速器和道具后没有更新?
我正在尝试从股票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;
}
};
相关文章