问题
Seen several questions about this but with many unclear and different answers.
I am rendering a list of items in the very first load of my component, and currently I'm triggering this fetch like so:
fetchMovies = () => {
console.log('component page:', this.props.movie.page);
this.props.getMoviesIfNeeded(this.props.movie.page);
};
handleScroll = throttle(() => {
let d = document.body;
let scrollTop = window.scrollY;
let windowHeight = window.innerHeight || document.documentElement.clientHeight;
let height = d.offsetHeight - windowHeight;
let scrollPercentage = (scrollTop / height);
// if the scroll is more than 90% from the top, load more content.
if (scrollPercentage > 0.90) {
// this.fetchMovies();
if (!this.props.movie.isFetching) {
this.props.increasePage();
}
}
}, 1000);
componentDidMount() {
if (this.props.movie.page === 1) {
this.fetchMovies();
}
window.addEventListener('scroll', this.handleScroll);
}
my problem with this is that naturally it is executed at every Route navigation to the component. (currently: list page => detail page => list page) and it is re-executed each time. I would like to remove this call to fetchMovies and move it to the initialState passed in:\
export default function configureStore() {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
return createStore(
reducers,
+ initialState, // there
composeEnhancers(applyMiddleware(thunk))
);
}
as described in the documentation: https://redux.js.org/recipes/configuring-your-store#the-solution-configurestore . In this case, where should the HTTP Request live? Currently, the fetching is done in my actions file:
export let getMovies = (page = 1) => async dispatch => {
let err, response;
dispatch(requestMovies(page));
[err, response] = await to(axios.get(`${apiUrls.base}/${apiUrls.theaters}`, {
params: {
page,
api_key: '36081eca9a2ced64d616c59681881626',
}
}));
console.log('request done with page:', page);
if (err) return dispatch(throwError(err));
debugger;
return dispatch(receiveMovies(response.data));// somewhere here I want to trigger another action that increases the page...?
};
My application is not a SSR app (NextJS) but plain simple React.
edit these are the other actions and reducers
// actions
function shouldFetchMovies(state, page) {
if (!state.movie.movies.length) {
return true;
} else if (state.movie.isFetching) {
return false;
} else {
return state.movie.movies;
}
}
export function getMoviesIfNeeded(page) {
return (dispatch, getState) => {
if (shouldFetchMovies(getState(), page)) {
return dispatch(getMovies(page));
}
}
}
// reducers
const defaultState = {
movies: [],
total: 0,
page: 1,
isFetching: false,
};
export default (state = defaultState, action) => {
switch (action.type) {
case 'INCREASED_PAGE':
return {
...state,
page: state.page + 1,
};
case 'REQUESTED_MOVIES':
return {
...state,
isFetching: true,
};
case 'RECEIVED_MOVIES':
return {
...state,
movies: [...state.movies, ...action.response.results],
// total: action.response.total_results,
isFetching: false,
};
default:
return state;
}
}
回答1:
initialState - is a object. It's not the place you should call any fetch operations. The best place for side-effects is componentDidMount lifecylce method. So your implementation for callling is correct.
If you are going to change redux state you should use reducers. You have to create reducer for the action you use in receiveMovies action creator which will update app state. There you can get data from your response and update any state values you need.
来源:https://stackoverflow.com/questions/61777920/how-do-i-fetch-the-initial-redux-state-from-an-api-response