admin管理员组文章数量:1125755
Well ok, it's probably not incorrect that the data is cached, but it's not what I want to happen. But I am stuck on how to correctly set up my custom data store the way I need.
I'm trying to set up a wp.data
custom data store to track a few things in my front-end, react, rendered app. It's integrating with some legacy WordPress that has a <select>
html element and I need to refresh the data store when the select value changes.
I'm getting stuck on 2 points and I suspect they are related.
1. If the select's value is 1, the product with ID = 1 is correctly fetched from the API. Same, if you switch the select to value 2. But then if you switch back to value/product ID = 1, the product in the data store is not updated... and I am fairly certain now that it's because the resolver's resolution (with that specific ID) was cached.
Here's my app's functional component:
import React from "react";
import { useState } from '@wordpress/element';
import { __ } from "@wordpress/i18n";
import { useSelect } from "@wordpress/data";
import { PRODUCTS_STORE_KEY } from "./data";
function App() {
const [ productId, setProductId ] = useState( 0 );
const handleChange = (e) => {
const productId = parseInt(e.target.value, 10) || e.target.value;
setProductId(productId);
};
// Get product from the store.
const { product } = useSelect(
( select ) => {
return {
product: select( PRODUCTS_STORE_KEY ).getProduct( productId ),
};
}, [ productId ]
);
console.debug('product', product);
return (
<div className="App">
<div>
<label>{__("Choose a product", "your-text-domain")}</label>
<select onChange={handleChange}>
<option value="0">{__("None", "your-text-domain")}</option>
<option value="1">{__("Product 1", "your-text-domain")}</option>
<option value="2">{__("Product 2", "your-text-domain")}</option>
<option value="3">{__("Product 3", "your-text-domain")}</option>
<option value="4">{__("Product 4", "your-text-domain")}</option>
<option value="5">{__("Product 5", "your-text-domain")}</option>
</select>
</div>
{product && (
<div>
<h2>{product.title}</h2>
<p>{product.description}</p>
<p>Price: {product.price}</p>
</div>
)}
</div>
);
}
export default App;
and here's my resolver:
/**
* Fetch a product object from the Store API.
*
* @param {number} productId Id of the product to retrieve.
*/
export function getProduct( productId ) {
return async ( { dispatch } ) => {
try {
let product = null;
if ( productId ) {
const response = await fetch( `/${productId}`);
product = await response.json();
dispatch.hydrateProduct( product );
return product;
}
} catch ( error ) {
// @todo: Handle an error here eventually.
console.error( error );
}
};
}
So (somehow) I could invalidate the cache using wp.data.dispatch( ‘data/products’ ).invalidateResolution( ‘getProduct’ );
. I am not at all clear on how/where to add this to my code, but also part
2. is that I don't want to invalidate the cache because I don't want to have to fetch the result from the API another time. If I have fetched product 1's data once, I should stash it somewhere and serve it locally the next time the select's value is equal to 1.
It should be clearer in the minimum, viable, example I have created here: /
As an MVE, using a custom data store is clearly overkill, but I will eventually need to track some custom data.
So, is there a different way to set up my resolver? or do I need to restructure my store?
Well ok, it's probably not incorrect that the data is cached, but it's not what I want to happen. But I am stuck on how to correctly set up my custom data store the way I need.
I'm trying to set up a wp.data
custom data store to track a few things in my front-end, react, rendered app. It's integrating with some legacy WordPress that has a <select>
html element and I need to refresh the data store when the select value changes.
I'm getting stuck on 2 points and I suspect they are related.
1. If the select's value is 1, the product with ID = 1 is correctly fetched from the API. Same, if you switch the select to value 2. But then if you switch back to value/product ID = 1, the product in the data store is not updated... and I am fairly certain now that it's because the resolver's resolution (with that specific ID) was cached.
Here's my app's functional component:
import React from "react";
import { useState } from '@wordpress/element';
import { __ } from "@wordpress/i18n";
import { useSelect } from "@wordpress/data";
import { PRODUCTS_STORE_KEY } from "./data";
function App() {
const [ productId, setProductId ] = useState( 0 );
const handleChange = (e) => {
const productId = parseInt(e.target.value, 10) || e.target.value;
setProductId(productId);
};
// Get product from the store.
const { product } = useSelect(
( select ) => {
return {
product: select( PRODUCTS_STORE_KEY ).getProduct( productId ),
};
}, [ productId ]
);
console.debug('product', product);
return (
<div className="App">
<div>
<label>{__("Choose a product", "your-text-domain")}</label>
<select onChange={handleChange}>
<option value="0">{__("None", "your-text-domain")}</option>
<option value="1">{__("Product 1", "your-text-domain")}</option>
<option value="2">{__("Product 2", "your-text-domain")}</option>
<option value="3">{__("Product 3", "your-text-domain")}</option>
<option value="4">{__("Product 4", "your-text-domain")}</option>
<option value="5">{__("Product 5", "your-text-domain")}</option>
</select>
</div>
{product && (
<div>
<h2>{product.title}</h2>
<p>{product.description}</p>
<p>Price: {product.price}</p>
</div>
)}
</div>
);
}
export default App;
and here's my resolver:
/**
* Fetch a product object from the Store API.
*
* @param {number} productId Id of the product to retrieve.
*/
export function getProduct( productId ) {
return async ( { dispatch } ) => {
try {
let product = null;
if ( productId ) {
const response = await fetch( `https://dummyjson.com/products/${productId}`);
product = await response.json();
dispatch.hydrateProduct( product );
return product;
}
} catch ( error ) {
// @todo: Handle an error here eventually.
console.error( error );
}
};
}
So (somehow) I could invalidate the cache using wp.data.dispatch( ‘data/products’ ).invalidateResolution( ‘getProduct’ );
. I am not at all clear on how/where to add this to my code, but also part
2. is that I don't want to invalidate the cache because I don't want to have to fetch the result from the API another time. If I have fetched product 1's data once, I should stash it somewhere and serve it locally the next time the select's value is equal to 1.
It should be clearer in the minimum, viable, example I have created here: https://nwy3j4.csb.app/
As an MVE, using a custom data store is clearly overkill, but I will eventually need to track some custom data.
So, is there a different way to set up my resolver? or do I need to restructure my store?
Share Improve this question asked Jan 30, 2024 at 2:33 helgathevikinghelgatheviking 14.5k8 gold badges64 silver badges115 bronze badges1 Answer
Reset to default 1Thanks for MVE, @helgatheviking! It was beneficial.
When wp.data
caches the resolvers, it also considers arguments. Here's what happens when following the reproduction steps for the bug:
- Selecting the first product resolves data, creates a cache for
getProduct(1)
, and sets a value for theproduct
state. - Selecting second does the same (cache:
getProduct(2)
) and sets a new value for theproduct
state. - When switching back to the first product,
wp.data
knows the resolution was successful, so it calls the selector. The selector returns the latestproduct
state for Product #2 set in step 2.
Solution: Use product ID as key when storing them in state, so selectors return correct data. Here's the updated fork - https://codesandbox.io/p/sandbox/mve-product-store-example-cached-resolve-value-forked-8lqv3r?file=%2Fsrc%2Fdata%2Findex.js.
P.S. You can check cached resolvers by running - select( storeName ).getCachedResolvers()
.
本文标签: javascriptuseSelect() plus resolver result is serving cached data incorrectly
版权声明:本文标题:javascript - useSelect() plus resolver result is serving cached data incorrectly 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736671666a1946955.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论