# Block and asset utilities

> Flatten verbose parameter values for assets and blocks with utilities provided by the Uniform Canvas package.

Source: https://docs.uniform.app/docs/guides/composition/rendering/blocks-assets

When you are working with a Block parameter or an Asset parameter in React or Vue, the Uniform prop will contain our common verbose value structure which looks like this:

```tsx
import { BlockValue, AssetParamValue } from '@uniformdev/canvas'

interface MyComponentProps {
  myblock: BlockValue
  myasset: AssetParamValue
}

function MyComponent({ myblock, myasset }) {
  console.log(myblock)
  // [{ fields: { title: { type: 'text', value: 'Hello' } } }, ...]
  console.log(myasset)
  // [{ fields: { url: { type: 'text', value: 'https://img...' } } }, ...]
  return (
    <div>
      {myblock?.map(
        (block, i) => <h2 key={i}>{block.fields?.title?.value}</h2>
      )}
      {!!myasset[0] 
        ? <img 
          alt={myasset[0].fields?.title?.value}
          src={myasset[0].fields?.url?.value} />
        : null
      }
    </div>
  )
}
```

Uniform components don't flatten these more complex parameters by default for:

1. **Performance:** Uniform structures have the potential for unlimited nesting which isn't always used within every context. This would result in unnecessary traversal of these nested trees.
2. **Flexibility:** The structure provides contextual data which might change the expected value depending on the context. Uniform also wants to prevent the loss of this data at the API level in case it's needed within UI components.
3. **The developer understands the contextual use-case best:** The decision of whether to flatten, and how much to flatten, is best left to the engineer.

## The flatten values utility

The [Canvas package](https://sdk.uniform.app/canvas) (`@uniformdev/canvas`) provides some helpful utility functions which make it easier to flatten and simplify the values from within verbose Uniform objects like asset, entry or block.

The utilities will also handle the possibility of empty values like `null` or `undefined` which is common in preview scenarios.

### Flatten values with blocks

If you are working with the block parameter it's likely you will be iterating over an array of blocks. If you take the verbose example above and use the `flattenValues` helper, you'll get:

```javascript
import { flattenValues } from '@uniformdev/canvas'

function MyComponent({ myblock, myasset }) {
  ...
  return (
    <div>
      {flattenValues(myblock)?.map(
        ({ title } = {}, i) => <h2 key={i}>{title}</h2>
      )}
      ...
    </div>
  )
}
```

This is especially helpful if you have atomic React or Vue components which expect simple, flattened props. You should be able to pass the block values directly to them.

### Flatten values with assets

If you are working with the asset parameter, you will have a similar need to work with arrays of assets. In this case you can follow the same process as with blocks.

It's also common to have an asset parameter which will only ever be a single asset. You can improve the verbose example above and use the `flattenValues` helper to make this simpler:

```javascript
import { flattenValues } from '@uniformdev/canvas'

function MyComponent({ myblock, myasset }) {
  ...
  const image = flattenValues(myasset, { toSingle: true })
  return (
    <div>
      ...
      {image
        ? <img alt={image.title} src={image.url} />
        : null
      }
    </div>
  )
}
```

This is helpful becuase it will return a single object with with flattened values rather than an array.

### Nested Blocks and Assets

Often, asset fields are nested inside a block and blocks can nest themselves. In this case, the `flattenValues` provides the `levels` option which defaults to `1`. This means that for most  use cases you won't need to use it.

If you have an asset field inside a block, the default setting will flatten the values on the asset as well as the block.

```javascript
import { flattenValues } from '@uniformdev/canvas'

// Default:
const myblockWithAsset = flattenValues(myblock)
// myblockWithAsset is:
[{
  title: "Hello",
  myasset: [
    {
      title: "hello",
      url: "https://img..."
    }
  ],
  mychildblock: [
    { title: "Hello" }
  ]
}]
```

If you need further levels of nesting there are a couple of options:

1. **Component based nesting (recommended):**

   To support infinite nesting of blocks, Uniform recommends using components. In this pattern, each component is responsible for flattening enough to feed the child level.

   ```jsx
   import { flattenValues } from '@uniformdev/canvas'

   function MyParentComponent({ myblocks }) {
     // set levels to 0 so that the child handles it's own
     // flatten values
     return (
       <div>
         {flattenValues(myblocks, { levels: 0 })?.map(
           ({ title, childblocks } = {}, i) => <>
             <h2 key={i}>{title}</h2>
             <MyChildComponent myblocks={childblocks} />
           </>
         )}
       </div>
     )
   }
   function MyChildComponent({ myblocks }) {
     return (
       <div>
         {flattenValues(myblocks)?.map(
           ({ title } = {}, i) => <h2 key={i}>{title}</h2>
         )}
       </div>
     )
   }
   ```
2. Use `levels` to specify a higher number or `Infinity`.

   ```jsx
   // Further Nesting:
   const deepNestedBlocks = flattenValues(myblock, { levels: 10 });
   ```

> **Other uses:**
>
> The `flattenValues` helper will also work on [components](https://docs.uniform.app/docs/guides/models/components) and [entries](https://docs.uniform.app/docs/guides/composition/entries), although this is usually handled for you by <Slot /> components.
