My use case is that I have a JSONField/mixedfield schema 13. Content types: Reference – Mastering Plone 6 development — Plone Training 2025 documentation with one of the subfields being a select field with a vocabulary. I noticed that if I have a non-mixedfield select field my component is passed a value that includes both the token and the title. But in the case of mixedfields I am only given the token value.
const ContactPhones = ({ phones }) => {
// JSONField select items do not come as an Object with title/token so we need to query @vocabulary
const dispatch = useDispatch(),
phoneTypeVocabName = 'ims.contacts.phone_types',
phoneTypes = useSelector((state) => state.vocabularies || {});
useEffect(() => {
let tokens = [];
phones.items.forEach(phone => {
tokens.push(phone.type);
})
dispatch(getVocabularyTokenTitle({ vocabNameOrURL: phoneTypeVocabName, tokens: tokens }));
}, [dispatch]);
console.log(phoneTypes)
const parsedPhones = phones.items.map(ph => {
return `${phoneTypes?.[phoneTypeVocabName]?.[ph.type] || ph.type}: ${ph.number}`
})
return (
<List id="phones" celled items={parsedPhones} />
)
}
In the above component I am attempting to use the "tokens" parameter to pass two tokens. This doesn't work, and I'm not entirely sure if it should. The function has a "tokens" parameter but it's not in the docstring. Here's the console log:
If I pass in a single token with the "token" parameter it works. The console log is below. But surely I wouldn't be expected to make a separate XHR for each phone type I've added?
Inspect the store for vocabularies.
If your vocabulary is present, you have access with useSelect.
If not, post again for details how to make it available.
No custom action/reducer necessary.
It's not present, that is why I am using the getVocabularyTokenTitle action above. I do not have any custom actions/reducers, this is one that comes from volto core. What I was hoping to be in the store is mapping vocab tokens to titles. I am able to get this if I pass in a single token, but not multiple.
In useEffect: getVocabulary(„myvocab“) to make the vocab available in the global store.
After everything is running as expected, check when and how offen the request is done and If this needs more attention than just firing in usEffect of the component to be efficient, not only effective.
I'm sorry, I don't think that answers me question. I was hoping to use getVocabularyTokenTitle I'm just not sure it works the way I want it to. getVocabulary returns the entire vocabulary - this is not ideal because it requires writing a mapping to convert the token to a title. IMO that should be handled by a REST API end point. getVocabularyTokenTitle seems like it is almost there, but not quite.
The trick is to load the store once with the vocabulary and read it for multiple tokens.
The store is global, access it in whatever component, this or the next page.
Comming from Plone Classic it took me days to get the pattern of the global store present.
As this is essential, I was curious how it would look like to enhance the training example 13. Content types: Reference – Mastering Plone 6 development — Plone Training 2025 documentation with a field, constrained by vocabulary.
Here is a draft that works. Hope you can translate it to your needs.
Thank you, that all makes sense. That is roughly what I ended up doing with the getVocabulary action. I'm still curious what the intent of the getVocabularyTokenTitles action is though...
Follow up question, this is really about Redux more than Plone I think. Given my below component, if I have multiple contacts that each use I get an XHR for each use. I only want to call @vocabulary once and have it update state and then just access that state. I think this is the point of dispatch/reducers, but I'm doing something wrong?
It looks like you have one component XY that renders multiple components Contact, each rendering one ContactPhones component. Now you want to dispatch getVocabulary only once per XY component as the call of getVocabulary is the same (same parameters) for all.
Dispatching getVocabulary in useEffect of XY would do this.
I see, so I had a misconception about dispatches work. I moved the phoneMap building to a custom hook and then called that on the parent component, and passed it down as a prop.