RN 0.59 TS 模板

更新时间:2023-10-12 08:00:15下载pdf

本文主要以 basic-ts-0.59 为例介绍了其包含的具体功能及如何使用。如需查看更多资源,请前往 tuya-panel-demo Github 仓库

说明: 此项目依赖 TYSdk.mobile.mobileInfo.appRnVersion 5.28 以上,如 App 版本过低,请前往 涂鸦面板-RN 重新下载。

目录

├── .babelrc ├── .eslintignore ├── .eslintrc.base.js ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .versionrc ├── CHANGELOG.md ├── README-zh_CN.md ├── README.md ├── index.android.js // 安卓入口 ├── index.ios.js // iOS 入口 ├── index.js // 安卓入口(为了兼容) ├── package.json ├── rn-cli.config.js ├── src │ ├── api // 放置项目中用到的一系列云端 API │ ├── components // 放置项目中用到的复用的功能组件 │ ├── composeLayout.tsx // 封装处理了面板内部所需要的一些`设备事件`和`设备信息` │ ├── config // 放置面板内部一些常用的配置文件 │ ├── i18n // 放置多语言配置文件 │ ├── main.tsx // 项目入口文件,继承自 `NavigatorLayout`,通过重写 `hookRoute` 方法将必要的配置传入,例如背景、topbar 等。重写 `renderScene` 方法控制路由跳转 │ ├── models // 放置 redux 相关的代码 │ ├── pages // 放置项目的各个页面级别的组件 │ ├── res // 放置本地资源,包括图片,svg path 等 │ └── utils // 放置面板内部会用到的常用工具方法等 ├── tsconfig.json // ts 配置文件 └── yarn.lock

核心模块介绍

src/api

放置项目中用到的一系列云端 API。

定义 API

import { TYSdk } from 'tuya-panel-kit'; // tips: TYSdk.apiRequest 提供了泛型支持可使代码更加美观 export const someApiFn = () => { return TYSdk.apiRequest<any>('tuya.some.api.name', {}); };

使用 API

import * as api from '@api'; api.someApiFn().then(data => console.log(data));

src/components

放置项目中用到的复用的功能组件

src/config

放置面板内部常用的配置文件

src/i18n

放置多语言配置文件,具体多余的使用方式可参考国际化多语言

src/models

放置 redux 相关的代码,内部的 common 模块封装了常用的 state 以及 actions。

  • dpState:当前设备的 DP 点状态

    • 类型定义:基于当前产品所拥有的功能点的对象
    • 如何获取:
    import { View } from 'react-native'; import { TYText } from 'tuya-panel-kit'; import { useSelector } from '@models'; const SomeFCComponent: React.FC = () => { const dpState = useSelector(state => state.dpState); return ( <View> <TYText text={JSON.stringify(dpState)} /> </View> ); };
    • 如何更新:
    import { View } from 'react-native'; import { useDispatch } from 'react-redux'; import { TYSdk, TYText, Button } from 'tuya-panel-kit'; import { useSelector, actions } from '@models'; const SomeFCComponent: React.FC = () => { const dispatch = useDispatch(); const handleClick = () => { dispatch(actions.common.updateDp({ yourDpCode: 'yourDpValue' })); // 也可以直接通过 TYSdk device 中的方法直接下发 // TYSdk.device.putDeviceData({ yourDpCode: 'yourDpValue' }); }; return ( <View> <Button text="下发 DP" onPress={handleClick} /> </View> ); };
  • devInfo:当前设备的信息

    import { View } from 'react-native'; import { TYText } from 'tuya-panel-kit'; import { useSelector } from '@models'; const SomeFCComponent: React.FC = () => { const devInfo = useSelector(state => state.devInfo); return ( <View> <TYText text={JSON.stringify(devInfo)} /> </View> ); };
    • 如何设置:devInfo 内部已完成信息维护,不建议业务单独处理。
  • logs:DP 点下发上报日志信息,仅该项目需要。

src/pages

放置项目的各个页面级别的组件,其中在本项目中内置了以下两个页面:

  • home:一个调试 DP 点的控制台,其中 consoleLayout 为 DP 下发和上报的日志输出组件、contentLayout 为 DP 的交互控制下方组件;
  • setting:一个基础的页面,仅用于展示如何在项目内部使用路由及路由相关基础配置功能;

src/res

放置本地资源,包括图片、svg path 等。可以通过 @res 引用其 index.ts 文件。src/res 内置了 read.js 文件可用于快速遍历新增图片文件生成 index.ts 文件导出,具体使用命令可参考下方示例。

$ node src/res/read.js [ 'button', 'button', 'tuya_decrease', 'tuya_goto_icon', 'tuya_increase', 'tuya_select_icon' ] const button = require('./button.png'); const tuya_decrease = require('./tuya_decrease.png'); const tuya_goto_icon = require('./tuya_goto_icon.png'); const tuya_increase = require('./tuya_increase.png'); const tuya_select_icon = require('./tuya_select_icon.png'); export default { button, tuya_decrease, tuya_goto_icon, tuya_increase, tuya_select_icon };

src/utils

放置面板内部的常用工具方法等。

src/composeLayout.tsx

封装处理了面板内部所需要的一些设备事件设备信息

高阶函数 composeLayout 支持实现以下功能:

  • 面板初始化时:composeLayout 处理原始的devInfo,初始化redux store
  • 面板运行时:composeLayout 监听设备变更相关的事件,并实时更新相应的redux store
  • 传入的componentredux store 关联。
import _ from "lodash"; import PropTypes from "prop-types"; import React, { Component } from "react"; import { Provider, connect } from "react-redux"; import { TYSdk, Theme } from "tuya-panel-kit"; import { devInfoChange, deviceChange, responseUpdateDp, } from "./redux/modules/common"; import theme from "./config/theme"; const TYEvent = TYSdk.event; const TYDevice = TYSdk.device; /** * * @param {Object} store - redux store * @param {ReactComponent} component - 需要连接到 redux store 的组件,通常为 main */ const composeLayout = (store, component) => { const NavigatorLayoutContainer = connect(_.identity)(component); const { dispatch } = store; /** * 此处监听了`设备数据变更`事件, * 每当 DP 点数据变更时,会将变更的 DP 点状态同步更新至 `redux`。 * 同理当设备信息变更时,也会将变更的设备信息值同步更新至 `redux`。 */ TYEvent.on("deviceDataChange", (data) => { switch (data.type) { case "dpData": dispatch(responseUpdateDp(data.payload)); break; default: dispatch(deviceChange(data.payload)); break; } }); /** * 此处监听了`网络状态变更事件`事件, * 每当设备信息变更时,会将变更的设备信息值同步更新至 `redux`。 */ TYEvent.on("networkStateChange", (data) => { dispatch(deviceChange(data)); }); class PanelComponent extends Component { static propTypes = { // eslint-disable-next-line devInfo: PropTypes.object.isRequired, }; /** * 如果面板进入时,`devInfo`已经存在(通常存在) * 这里会调用 setDeviceInfo 将原始的 devInfo 处理一下,并置入`redux` * * 如果面板进入时,`devInfo` 不存在, * 那么调用 getDeviceInfo 异步获取处理完成的 `devInfo`,并置入`redux` */ constructor(props) { super(props); if (props && props.devInfo && props.devInfo.devId) { TYDevice.setDeviceInfo(props.devInfo); TYDevice.getDeviceInfo().then((data) => dispatch(devInfoChange(data))); // eslint-disable-next-line } else if (props.preload) { // do something } else { TYDevice.getDeviceInfo().then((data) => dispatch(devInfoChange(data))); } } render() { return ( <Provider store={store}> <Theme theme={theme}> <NavigatorLayoutContainer /> </Theme> </Provider> ); } } return PanelComponent; }; export default composeLayout;

src/main.tsx

MainLayout 入口组件继承NavigatorLayout,主要帮助面板内部管理多页面。

import React from 'react'; import { StatusBar } from 'react-native'; import { Dispatch } from 'redux'; import { TYSdk, NavigatorLayout, NavigationOptions, DeprecatedNavigator, DeprecatedNavigatorRoute, } from 'tuya-panel-kit'; import composeLayout from './composeLayout'; import { store, ReduxState } from './models'; import Home from './pages/home'; import Setting from './pages/setting'; console.disableYellowBox = true; type Props = ReduxState & { dispatch: Dispatch }; // 谨慎使用,生成环境上不要开启,console 打印层次过深会导致性能问题 // if (__DEV__) { // console.log('TYSdk :', TYSdk); // } class MainLayout extends NavigatorLayout<Props> { /** * * @desc hookRoute 可以在这里针对特定路由执行控制处理,可控制的参数参考 [NavigationOptions](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/tuya-panel-kit/index.d.ts) 类型描述 */ hookRoute(route: DeprecatedNavigatorRoute): NavigationOptions { const routeProps: NavigationOptions = {}; switch (route.id) { case 'main': break; case 'setting': routeProps.title = 'Setting'; routeProps.background = { '3%': '#f82232', '90%': '#FF624C', }; break; default: break; } return { ...routeProps, renderStatusBar: () => <StatusBar barStyle="default" />, }; } /** * @desc * 在此您可以通过 route 中的 ID 判断使用哪个页面组件 * 如果有额外的 props 需要传递给页面组件的,可以在此进行传递 * 注意:route 参数来自于 TYSdk.Navigator.push * 如果调用了 TYSdk.Navigator.push({ id: 'setting', title: 'Setting Page' }); * 则会在推入路由栈时 hookRoute 和 renderScene 这个周期里会接受到 route = { id: 'setting', title: 'Setting Page' }, * 但要注意的是,首页的 route 参数是固定的,为 { 'id': 'main', 'initialRoute': true } * * @param {Object} route - route对象 * @param {object} navigator - Navigator对象,具体使用方法可参考https://facebook.github.io/react-native/docs/0.43/navigator.html */ renderScene(route: DeprecatedNavigatorRoute, navigator: DeprecatedNavigator) { let component; switch (route.id) { case 'main': component = <Home />; break; case 'setting': component = <Setting />; break; default: break; } return component; } } export default composeLayout(store, MainLayout);