Is there an equivalent for "withParent" in Sanity v3? Helper function to get parent context of a field for a custom input component in a deeply nested document.

2 replies
Last updated: Feb 6, 2023
Heyho everyone.
In v2 we were able to wrap e.g. an inputComponent using withParent or withDocument:

import { withParent } from 'sanity'
function CategoryInput(props){
  const { category, title, content } = props?.parent || {};
  // ...
}
The schema in v2:

// ...
{
  name: "items",
  type: "reference",
  to: [{type: 'news'},{type: 'product'}],
  inputComponent: withParent(CategoryInput)
}
// ...
Now in v3 we have the
useFormValue hook :
import { useFormValue } from 'sanity'
function CategoryInput(props){
  const { category, title, content } = useFormValue([])['content'][6]['category']['items'] || {};
  // useFormValue([]) only gives me the document, and I need to narrow down manually
  // ...
}
The schema in v3:

// ...
{
  name: "items",
  type: "reference",
  to: [{type: 'news'},{type: 'product'}],
  components: {
    input: CategoryInput
  }
}
// ...
In the above scenario I have an input component which is part of a Portable Text field. The portable text itself is part of a document of type “page”, where its name is “content”. But in another document its name may be different. So in v3 I have to worry about the context of a grandparent.


useFormValue seems to replace only “withDocument”.But for a nested context it’s impractical, as you would need to now the entire tree or filter it to get the parent context you are looking for.


So is there an equivalent for “withParent” in v3?
Feb 6, 2023, 3:48 PM
Found a solution:The component props contain a “path” value, which we can use to traverse the document object tree.

Here’s a a little helper function I developed to get the parent context of a field for a custom input component in a deeply nested document in Sanity v3:


import { useFormValue } from 'sanity';

const CustomInput = React.forwardRef((props, ref) => {

  const parent = accessNestedValue(
     useFormValue([]),
     props.path
  );

});

// the helper function
function accessNestedValue(obj, keys) {
  let currentKey = keys[0];
  let restKeys = keys.slice(1);
  
  while(restKeys.length) {
    if (typeof currentKey === 'object') {
      const keysKey = Object.keys(currentKey)[0];
      const keysValue = currentKey[keysKey];      
      obj = obj.find( el => el[keysKey] === keysValue );
    } else if (!obj.hasOwnProperty(currentKey)) {
      return undefined;
    } else {
      obj = obj[currentKey];
    }
    currentKey = restKeys[0];
    restKeys = restKeys.slice(1);
  }

  return obj;
}
Feb 6, 2023, 9:00 PM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?