---
name: "useStructuredProps"
mode: "api"
versionRequirements:
  - { name: "@ray-js/panel-sdk", version: "1.10.0" }
title: "useStructuredProps - 基于 sdm 实例及 dp-kit 拦截器实现"
summary: "useStructuredProps 是 @ray-js/panel-sdk 提供的 React Hook，基于 sdm 实例及 dp-kit 拦截器实现，能根据 protocols 协议文件自动解析复杂类型功能点（如 colour_data 解析为 hue/saturation/value），通过 selector 订阅状态变化驱动重渲染，内置 shallow equal 并支持自定义 equalityFn，只返回配置了协议规则的功能点，支持单设备和群组。"
questions:
  - "怎么监听结构化复杂类型的dp状态变化？怎么监听raw类型的功能点状态变化？"
  - "useStructuredProps 如何根据 protocols 协议文件自动解析 colour_data 为 hue、saturation、value 结构？"
  - "useStructuredProps 只返回配置了协议规则的功能点，不返回基础数据类型功能点，这是为什么？"
  - "使用 useStructuredProps 前需要先配置接入 dp-kit 拦截器，具体在哪里配置？"
  - "useStructuredProps 内置 shallow equal 浅比较，如何通过自定义 equalityFn 仅在 colour.hue 变化时重渲染？"
  - "useStructuredProps 的 selector 函数参数 props 的类型 GetStructuredDpState 是如何根据协议推导的？"
  - "useStructuredProps 与 useProps 的区别是什么（结构化复杂类型 vs 基础功能点）？"
  - "useStructuredProps 同时支持单设备和群组设备，两种环境下使用方式一致吗？"
  - "useStructuredProps 的 TypeScript 泛型 DpKitProtocols 和 DpValue 分别代表什么？"
  - "如何通过 useStructuredProps(props => props.colour_data) 订阅彩光功能点的实时状态？"
  - "useStructuredProps 的更多信息参考 dp-kit 拦截器文档，dp-kit 提供了哪些功能点处理能力？"
---

<div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
  <span style={{ backgroundColor: '#52c41a', color: 'white', padding: '2px 8px', borderRadius: '4px', fontSize: '12px' }}>单设备支持</span>
  <span style={{ backgroundColor: '#52c41a', color: 'white', padding: '2px 8px', borderRadius: '4px', fontSize: '12px' }}>群组支持</span>
</div>

## useStructuredProps

> [VERSION] @ray-js/panel-sdk >= 1.10.0

> 💡 基于 sdm 实例及 dp-kit 拦截器实现。必须在 SdmProvider 内部使用。
> 使用前请注意检查项目是否已挂载了 SdmProvider，项目接入可参考 [智能设备模型 - 使用](/cn/miniapp/solution-panel/ability/common/sdm/usage)，全新项目可直接基于 [public-sdm](https://github.com/Tuya-Community/tuya-ray-materials/tree/main/template/PublicSdmTemplate) 示例项目进行开发。
> 使用前请注意检查是否已配置接入了 dp-kit 拦截器，项目接入可参考 [拦截器 - 使用](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/usage)。
> 出于 hooks 功能单一性和稳定性考虑，useStructuredProps 只会返回配置了协议规则的功能点，不会返回基础数据类型功能点。
> 典型场景：colour_data 等复合字符串字段，dp-kit 根据 protocols 协议自动解析为
> { hue, saturation, value } 等结构化对象。

### 描述

获取经 dp-kit 协议解析后的结构化功能点状态，状态变更时驱动组件重新渲染

### 参数

`Params`

| 参数 | 类型 | 必填 | 描述 |
| --- | --- | --- | --- |
| `selector` | `(structuredProps: object) => any` | 否 | 选择器函数，入参为结构化状态对象（每个 key 的值类型由 protocols 中对应 Transformer.parser() 的返回值决定），返回需要订阅的部分；不传则返回全部结构化功能点状态，注意不会返回基础数据类型功能点。 |
| `equalityFn` | `(prev: any, next: any) => boolean` | 否 | 自定义比较函数，入参为 selector 前后两次的返回值，返回 true 则不触发重渲染，默认 shallow equal |

### 返回值

类型: `any`

selector 的返回值，其类型由 selector 决定；未传 selector 时返回完整的结构化状态对象（每个 key 的值类型 = 对应 Transformer.parser() 的返回值类型）

### 示例代码

#### 完整接入链路（以照明 colour_data 为例）

```ts
// ---- 1. Parser：SDK 内置 ColourTransformer 源码参考 ----
// Transformer 接口：{ uuid, defaultValue, parser(dpStr) → T, formatter(data: T) → string }
// parser 的返回值类型 T 决定了 useStructuredProps 中对应 DP code 的结构化类型
// 自定义 parser 同理，实现 parser + formatter 即可
type TColorData = { hue: number; saturation: number; value: number };

class ColourTransformer implements Transformer<TColorData> {
  defaultValue = { hue: 10, saturation: 1000, value: 1000 };
  uuid = 'colour_data';

  // parser 返回 TColorData → useStructuredProps 中 props.colour_data 即为此类型
  parser(value: string): TColorData {
    if (value.length !== 12) return this.defaultValue;
    const step = generateDpStrStep(value);
    return { hue: step(4).value, saturation: step(4).value, value: step(4).value };
  }

  formatter(data: TColorData) {
    const { hue, saturation, value } = data;
    return `${decimalToHex(hue, 4)}${decimalToHex(saturation, 4)}${decimalToHex(value, 4)}`;
  }
}

// ---- 2. devices/protocols/index.ts：实例化 parser 并映射到 DP code ----
import { protocols as sdkProtocols } from '@ray-js/panel-sdk';
import { lampSchemaMap } from '../schema';

export const protocols = {
  // 实际变量名称为 colour_data，映射到 DP code
  [lampSchemaMap.colour_data.code]: new sdkProtocols.ColourTransformer(),
};

// ---- 3. devices/index.ts：创建 dpKit 并传给 sdm 实例 ----
import { SmartDeviceModel, createDpKit } from '@ray-js/panel-sdk';
import { protocols } from '@/devices/protocols';

export const dpKit = createDpKit({ protocols });
export const devices = {
  lamp: new SmartDeviceModel({ interceptors: dpKit.interceptors }),
};

// ---- 4. 页面组件：通过 useStructuredProps 消费结构化数据 ----
// props.colour_data 的类型 = ColourTransformer.parser() 的返回值 TColorData
// 即 { hue: number; saturation: number; value: number }
import { useStructuredProps } from '@ray-js/panel-sdk';
export default function Home() {
  const colour = useStructuredProps(props => props.colour_data);
  return (
    <View>
      <View>hue: {colour.hue}</View>
      <View>saturation: {colour.saturation}</View>
      <View>value: {colour.value}</View>
    </View>
  );
}
```

#### 自定义 rerender

```tsx
import React from 'react';
import { View } from '@ray-js/ray';
import { useStructuredProps } from '@ray-js/panel-sdk';

export default function Home() {
  const dpState = useStructuredProps(
    d => d,
    (prevDpState, nextDpState) => prevDpState.colour_data?.hue === nextDpState.colour_data?.hue, // 只会在返回 false 时 rerender
  );
  return (
    <View>
      <View>hue: {dpState.colour_data?.hue}</View>
      <View>saturation: {dpState.colour_data?.saturation}</View>
      <View>value: {dpState.colour_data?.value}</View>
    </View>
  );
}
```
