given my custom store, when I try to use readItems selector, I am always getting default store state. Selector works fine (tested in console with wp.data.select), however, it takes some time to catch values asynchronously I presume useSelect memoizes first returned value which is default store state and does not respond to store changes.
How to fix this?
Beginning of block edit function:
const LECTURERS_TABLE = 'tla_mit_lecturers';
export default function Edit(props) {
const { attributes, setAttributes } = props;
const allItems = useSelect(select => select('REST-extra_table').readItems(LECTURERS_TABLE));
Store:
import apiFetch from '@wordpress/api-fetch';
import { createReduxStore, register } from '@wordpress/data';
/**
* returns table id from table name
* @param {} table
*/
function getTableId(table) {
if (! table) {
console.log('Table name not supplied for API');
return undefined;
}
const tableId = tableIds.indexOf(table);
if (tableId == -1) {
console.log('Wrong table name supplied to the API');
return undefined;
}
return tableId;
}
// items is array of tables - item['table_name'][index] is individual item
const tableIds = [
'tla_mit_lecturers',
]
const DEFAULT_STATE = {
tables: [
['default']
],
};
const actions = {
*createItem( item, table ) {
const tableId = getTableId(table);
const retValue = yield actions.fetchFromAPI(
{
path: '/extra_table/v1/item?table=' + table,
method: 'POST',
data: item
}
);
// retValue should be ID if insert is successful
return retValue ?
{
type: 'CREATE_ITEM',
item: {ID: retValue, ...item},
tableId
} :
{
type: 'FETCH_ERROR',
error: 'unknown'
};
},
*deleteItem( ID, table ) {
const tableId = getTableId(table);
const retValue = yield actions.fetchFromAPI(
{
path: '/extra_table/v1/item?table=' + table + '&ID=' + ID,
method: 'DELETE'
}
);
return retValue ?
{
type: 'DELETE_ITEM',
tableId,
ID
} :
{
type: 'FETCH_ERROR',
error: 'unknown'
};
},
*updateItem( ID, item, table ) {
const tableId = getTableId(table);
const retValue = yield actions.fetchFromAPI(
{
path: '/extra_table/v1/item?table=' + table + '&ID=' + ID,
method: 'PUT',
data: item
}
);
return retValue ?
{
type: 'UPDATE_ITEM',
item: {ID, ...item},
ID,
tableId
} :
{
type: 'FETCH_ERROR',
error: 'unknown'
};
},
// action to set item values - hydrate in https://unfoldingneurons.com/2020/wordpress-data-store-properties-resolvers
setItem( item, tableId ) {
return {
type: 'SET_ITEM',
item,
tableId
};
},
// action to set item values - hydrate in https://unfoldingneurons.com/2020/wordpress-data-store-properties-resolvers
setAllItems( items, tableId ) {
return {
type: 'SET_ITEMS',
items,
tableId
};
},
fetchFromAPI( action ) {
return {
type: 'FETCH_FROM_API',
path: action.path,
method: action.method,
data: action.data,
tableId: action.tableId
};
}
};
const store = createReduxStore( 'REST-extra_table', {
reducer( state = DEFAULT_STATE, action ) {
switch ( action.type ) {
case 'CREATE_ITEM':
return {
...state,
tables: Object.assign([...state.tables], {[action.tableId]: [...state.tables[action.tableId], action.item] })
};
case 'UPDATE_ITEM':
return {
...state,
tables: Object.assign(
[...state.tables],
{[action.tableId]:
Object.assign(
state.tables[action.tableId],
{[state.tables[action.tableId].findIndex(el => el.ID === action.ID)]: action.item}
)
})
};
case 'DELETE_ITEM':
return {
...state,
tables: Object.assign([...state.tables], {[action.tableId]: state.tables[action.tableId].filter((el) => el.ID !== action.ID) })
};
// hydrate
case 'SET_ITEM':
return {
...state,
tables: Object.assign([...state.tables], {[action.tableId]: [...state.tables[action.tableId], action.item] })
}
case 'SET_ITEMS':
return {
...state,
tables: Object.assign([...state.tables], {[action.tableId]: [...action.items] })
}
case 'FETCH_ERROR':
console.log('AJAX fetch error, code: ' + action.error);
return state;
}
// console.error('Table name is not given!!! '+action.type)
return state;
},
actions,
selectors: {
readItem( state, ID, table ) {
const tableId = getTableId(table);
if (tableId === undefined)
return undefined;
if (state.tables[tableId])
return state.tables[tableId].find(el => el.ID == ID);
else
return undefined;
},
readItems( state, table ) {
const tableId = getTableId(table);
if (tableId === undefined)
return undefined;
// return empty array if state.tables does not exist
if (! state.tables[tableId])
console.error('Requested table does not exist in state!');
return state.tables[tableId] || undefined;
},
},
controls: {
FETCH_FROM_API( action ) {
return apiFetch(
{
path: action.path,
// path: action.path,
method: action.method,
credentials: 'same-origin',
mode:'same-origin',
// headers: {
// 'Content-Type': 'application/json'
// },
data: action.data
} );
},
},
resolvers: {
*readItem( ID, table ) {
const tableId = getTableId(table);
const item = yield actions.fetchFromAPI(
{
path: '/extra_table/v1/item?table=' + table + '&ID=' + ID,
method: 'GET',
data: null,
tableId
}
);
return item !== undefined ? actions.setItem( item, tableId ) : undefined;
},
*readItems( table ) {
const tableId = getTableId(table);
const allItems = yield actions.fetchFromAPI({
path: '/extra_table/v1/all_items?table=' + table,
method: 'GET',
data: null,
tableId
});
return allItems !== undefined ? actions.setAllItems( allItems, tableId ) : undefined;
},
},
} );
register( store );