Answer the question
In order to leave comments, you need to log in
Are state changes late (HOOKS + CONTEXT)?
After clicking on the button in Paginator, the pageChanged function is triggered. It correctly passes the currentPage value from the Pagination component. After that, the fetchItems function is executed, which should catch the necessary records from the api, but it catches the previous records, because the state did not have time to change for some reason. After pressing the button again, the correct data is already displayed.
Here is the component
import React, { useEffect, useContext } from 'react'
import Loader from '../../components/UI/Loader/Loader'
import { Paginator } from '../../components/UI/Paginator/Paginator'
import { Layout } from '../Layout/Layout'
import { Card } from '../../components/Card/Card'
import { Alert } from '../../components/Alert/Alert'
import { ItemsContext } from '../../context/items/ItemsContext'
export const Items = () => {
const items = useContext(ItemsContext)
useEffect(() => {
items.fetchItems(true)
}, [])
const pageChanged = (index) => {
items.setCurrentPage(index)
items.fetchItems(false)
console.log('Items',index)
console.log('State',items.currentPage)
}
const renderCards = () => {
return items.items.map((item, index) => {
return (
<Card
key={item.id}
item={item}
// addItemToBasket={this.props.addItemToBasket}
id={index}
/>
)
})
}
return (
<Layout>
<Paginator
totalItemsCount={items.totalItemsCount}
pageSize={items.pageSize}
currentPage={items.currentPage}
pageChanged={pageChanged}
portionSize={3}
/>
<div className="card-group row">
{
items.loading || items.items.length === 0
? <Loader />
: renderCards()
}
</div>
<Alert />
</Layout>
)
}
import { createContext } from 'react'
export const ItemsContext = createContext()
import {
SET_LOADING,
FETCH_ITEMS_SUCCESS,
FETCH_ERROR,
SET_CURRENT_PAGE,
SET_TOTAL_COUNT,
FETCH_ITEM_BY_ID_SUCCESS
} from '../types'
const handlers = {
[SET_LOADING]: state => ({...state, loading: true}),
[FETCH_ITEMS_SUCCESS]: (state, {payload}) => ({...state, items: payload, loading: false}),
[FETCH_ITEM_BY_ID_SUCCESS]: (state, {payload}) => ({...state, item: payload, loading: false}),
[FETCH_ERROR]: (state, {payload}) => ({...state, error: payload, loading: false}),
[SET_CURRENT_PAGE]: (state, {payload}) => ({...state, currentPage: payload}),
[SET_TOTAL_COUNT]: (state, {payload}) => ({...state, totalItemsCount: payload}),
DEFAULT: state => state
}
export const ItemsReducer = (state, action) => {
const handler = handlers[action.type] || handlers.DEFAULT
return handler(state, action)
}
import React, { useReducer } from 'react'
import axios from 'axios'
import { ItemsContext } from './ItemsContext'
import { ItemsReducer } from './ItemsReducer'
import {
SET_LOADING,
FETCH_ITEMS_SUCCESS,
FETCH_ERROR,
SET_CURRENT_PAGE,
SET_TOTAL_COUNT,
FETCH_ITEM_BY_ID_SUCCESS
} from '../types'
export const ItemsState = ({ children }) => {
const initialState = {
items: [],
item: null,
pageSize: 3,
currentPage: 1,
totalItemsCount: 0,
loading: false,
error: null
// basket: []
}
const [state, dispatch] = useReducer(ItemsReducer, initialState)
const fetchItems = async bool => {
setLoading()
try {
console.log('ItemsState', state.currentPage)
const response = await axios.get(`https://reqres.in/api/users?page=${state.currentPage}&per_page=${state.pageSize}`)
fetchItemsSuccess(response.data.data)
if (bool) {
setTotalCount(response.data.total)
}
} catch (e) {
fetchError(e)
}
}
const fetchItemById = async id => {
setLoading()
try {
const response = await axios.get(`https://reqres.in/api/users/${id}`)
fetchItemByIdSuccess(response.data.data)
} catch (e) {
fetchError(e)
}
}
const fetchItemByIdSuccess = (item) => dispatch({ type: FETCH_ITEM_BY_ID_SUCCESS, payload: item })
const fetchItemsSuccess = (items) => dispatch({ type: FETCH_ITEMS_SUCCESS, payload: items })
const fetchError = (e) => dispatch({ type: FETCH_ERROR, payload: e })
const setCurrentPage = (currentPage) => {
dispatch({ type: SET_CURRENT_PAGE, payload: currentPage })
console.log('setCurrentPage', currentPage)
}
const setLoading = () => dispatch({ type: SET_LOADING })
const setTotalCount = (totalItemsCount) => dispatch({ type: SET_TOTAL_COUNT, payload: totalItemsCount })
const { items, item, pageSize, currentPage, totalItemsCount, loading } = state
return (
<ItemsContext.Provider value={{
fetchItems,
fetchItemById,
setCurrentPage,
setTotalCount,
items, item, pageSize, currentPage, totalItemsCount, loading
}}>
{children}
</ItemsContext.Provider>
)
}
Answer the question
In order to leave comments, you need to log in
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question