【发布时间】:2021-07-09 01:37:33
【问题描述】:
我正在研究 redux-saga,我想从以下位置获取数据:
https://jsonplaceholder.typicode.com/posts
在我的 redux 文件夹中,我有以下内容:
(可以在这个github仓库中查看 https://github.com/jotasenator/redux-saga-fetching-example/tree/main/src)
\src\redux\api.js
import axios from 'axios'
export const loadPostApi = async () => {
await axios.get(`https://jsonplaceholder.typicode.com/posts`)
}
对相关地址的获取请求
src\redux\app.actions.js
export const loadPostStart = () => ({
type: 'LOAD_POST_START',
})
export const loadPostSuccess = (posts) => ({
type: 'LOAD_POST_SUCCESS',
payload: posts,
})
export const loadPostFail = (error) => ({
type: 'LOAD_POST_FAIL',
payload: error,
})
这些是动作函数
src\redux\app.reducer.js
const INITIAL_STATE = {
loading: false,
posts: [],
errors: null,
}
export const appReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'LOAD_POST_START':
return {
...state,
loading: true,
}
case 'LOAD_POST_SUCCESS':
return {
...state,
posts: action.payload,
loading: false,
}
case 'LOAD_POST_FAIL':
return {
...state,
errors: action.payload,
loading: false,
}
default:
return state;
}
}
获取、更新状态的reducer,
src\redux\counterReducer.js
import { types } from "./types";
const initialState = {
value: 0
}
export const counterReducer = (state = initialState, action) => {
switch (action.type) {
case types.adicionar:
return {
...state,
value: state.value + 1
}
case types.resetear:
return {
...state,
value: 0
}
case types.restar:
return {
...state,
value: state.value - 1
}
default:
return state
}
}
这是counter app的reducer,方法不同,类型被隔离在另一个文件中
src\redux\rootReducer.js
import { combineReducers } from 'redux'
import { counterReducer } from './counterReducer'
import { appReducer } from './app.reducer'
export const rootReducer = combineReducers({
counterReducer,
appReducer
})
用于收集 reducer 的 rootReducer
src\redux\sagas.js
import { put, takeLatest, call } from 'redux-saga/effects'
import { loadPostApi } from './api'
import { loadPostFail, loadPostSuccess } from './app.actions'
export function* onLoadPostStartAsync() {
try {
const response = yield call(loadPostApi)
yield put(loadPostSuccess(response.data))
} catch (error) {
yield put(loadPostFail(error))
}
}
export function* onLoadPost() {
yield takeLatest('LOAD_POST_START', onLoadPostStartAsync)
}
export default function* rootSaga() {
yield ([
onLoadPost(),
])
}
saga onLoadPostStartAsync 在 rootSaga 中由 saga onLoadPost 调用
src\redux\store.js
import { applyMiddleware, compose, createStore } from "redux";
import createSagaMiddleware from 'redux-saga'
import { rootReducer } from "./rootReducer";
import rootSaga from "./sagas";
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
export const store = createStore(rootReducer, enhancer)
sagaMiddleware.run(rootSaga)
这是带有 redux_devtool_extension、reducers 和运行 rootSaga 的商店
src\redux\types.js
export const types = {
adicionar: 'ADICIONAR',
resetear: 'RESETEAR',
restar: 'RESTAR'
}
这些是 counterApp reducer 的类型
src\Counter.js
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
export const Counter = () => {
const dispatch = useDispatch()
const { value } = useSelector(state => state.counterReducer)
const handleAdicionar = () => {
dispatch({ type: 'ADICIONAR' })
}
const handleResetear = () => {
(value !== 0) && dispatch({ type: 'RESETEAR' })
}
const handleRestar = () => {
dispatch({ type: 'RESTAR' })
}
console.log(value)
return (
<div>
<button onClick={handleAdicionar}>Adicionar</button>
{' '}
<button onClick={handleResetear}>Resetear</button>
{' '}
<button onClick={handleRestar}>Restar</button>
<hr />
</div>
)
}
这是 Counter 组件,它工作正常
src\Fetching.js
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { loadPostStart } from './redux/app.actions'
export const Fetching = () => {
const dispatch = useDispatch()
const fetchPost = () => {
dispatch(loadPostStart())
}
const state = useSelector(state => state.appReducer)
console.log(state)
return (
<>
<h1>Fetching from https://jsonplaceholder.typicode.com</h1>
<button onClick={fetchPost}>Fetching</button>
{
!state.loading && state.posts.map((post) => (
<li key={post.id}><h2>{post.title}</h2></li>
))
}
</>
)
}
Fetching 组件点击按钮调用 fetchPost 函数,该函数调度 loadPostStart() 函数,这与调度 {type: 'LOAD_POST_START'} 相同,但点击时这里没有任何反应,这里没有任何内容https://jsonplaceholder.typicode.com/posts
src\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { store } from './redux/store';
import { Provider } from "react-redux";
import { Unificator } from './Unificator';
ReactDOM.render(
<Provider store={store}>
<Unificator />
</Provider>,
document.getElementById('root')
);
组件 Unificator 有 Counter 和 Fetching 组件
src\Unificator.js
import React from 'react'
import { Counter } from './Counter'
import { Fetching } from './Fetching'
export const Unificator = () => {
return (
<div>
<Counter />
<Fetching />
</div>
)
}
如你所见,大概有两个reducer,一个是著名的counter,另一个是fetching issue,不知道是怎么回事,没有获取数据
显然,我在这里做错了......看不到哪里
【问题讨论】:
-
传奇会被触发吗?
-
我怎么知道?,我可以说不,但是调度是好的,可以在redux-devTools看到它
标签: reactjs react-redux redux-saga