如果我已经第二次调用请求,我该如何fetchMagazineListDetail函数修饰记忆 这个参数存在,我不想发送请求。
export const fetchMagazineListDetail = (id, paginate) => {
return dispatch => {
dispatch(fetchMagazineListDetailBegin());
fetch(`http://localhost:3003/magazine/${paginate}`)
.then(res => res.json())
.then(res => {
if(res.error) {
throw(res.error);
}
dispatch(fetchMagazineListDetailSuccess(res));
return res;
})
.catch(error => {
dispatch(fetchMagazineListDetailError(error));
})
}
}
Thanks in advance
您可以对操作进行分组,而不必在已分派操作时将其分派。根据缓存的不同,您可以在渲染期间,应用程序活动期间或本地存储中保留结果:
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;
const { useEffect, useMemo, useState } = React;
const { produce } = immer;
//group promise returning function
const createGroup = (cache) => (
fn,
getKey = (...x) => JSON.stringify(x)
) => (...args) => {
const key = getKey(args);
let result = cache.get(key);
if (result) {
return result;
}
//no cache
result = Promise.resolve(fn.apply(null, args)).then(
(r) => {
cache.resolved(key); //tell cache promise is done
return r;
},
(e) => {
cache.resolve(key); //tell cache promise is done
return Promise.reject(e);
}
);
cache.set(key, result);
return result;
};
//thunk action creators are not (...args)=>result but
// (...args)=>(dispatch,getState)=>result
// so here is how we group thunk actions
const createGroupedThunkAction = (thunkAction, cache) => {
const group = createGroup(
cache
)((args, dispatch, getState) =>
thunkAction.apply(null, args)(dispatch, getState)
);
return (...args) => (dispatch, getState) => {
return group(args, dispatch, getState);
};
};
//permanent memory cache store creator
const createPermanentMemoryCache = (cache = new Map()) => {
return {
get: (key) => cache.get(key),
set: (key, value) => cache.set(key, value),
resolved: (x) => x,
};
};
const NOT_REQUESTED = { requested: false };
const initialState = { data: {} };
//action types
const BEGIN = 'BEGIN';
const SUCCESS = 'SUCCESS';
//action creators
const fetchMagazineListDetail = createGroupedThunkAction(
(id) => {
return (dispatch) => {
//return a promise
return Promise.resolve().then(() => {
dispatch({ type: BEGIN, payload: { id } });
setTimeout(() =>
dispatch({ type: SUCCESS, payload: { id } })
);
});
};
},
createPermanentMemoryCache()
);
const reducer = (state, { type, payload }) => {
if (type === BEGIN) {
return produce(state, (draft) => {
const { id } = payload;
draft.data[id] = { ...state.data[id] };
draft.data[id].loading = true;
draft.data[id].requested = true;
});
}
if (type === SUCCESS) {
const { id } = payload;
return produce(state, (draft) => {
draft.data[id].loading = false;
draft.data[id].requested = true;
draft.data[id].result = payload;
});
}
return state;
};
//selectors
const selectData = (state) => state.data;
const crateSelectDataById = (id) =>
createSelector([selectData], (data) =>
data[id] ? data[id] : NOT_REQUESTED
);
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(
//thunk
({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
}
)
)
);
const Data = React.memo(function Data({ id }) {
const dispatch = useDispatch();
const selectDataById = useMemo(
() => crateSelectDataById(id),
[id]
);
const result = useSelector(selectDataById);
useEffect(() => {
if (!result.requested) {
dispatch(fetchMagazineListDetail(id));
}
}, [dispatch, id, result.requested]);
return <pre>{JSON.stringify(result, undefined, 2)}</pre>;
});
const App = () => {
const [id, setId] = useState(1);
return (
<div>
<select
value={id}
onChange={(e) => setId(e.target.value)}
>
<option value={1}>1</option>
<option value={2}>2</option>
</select>
<Data id={id} />
<Data id={id} />
</div>
);
};
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<script src="https://unpkg.com/immer@7.0.5/dist/immer.umd.production.min.js"></script>
<div id="root"></div>