RN 0.59 TS Template

Last Updated on : 2023-10-12 08:00:15download

This topic uses basic-ts-0.59 basic as an example, it introduces the specific features and how to use them. For more resources, please go to tuya-panel-demo GitHub repository.

This project depends on TYSdk.mobile.mobileInfo.appRnVersion 5.28 or later. If the app version is too old, please go to Tuya Panel - RN and download it again.

Table of contents

├── .babelrc ├── .eslintignore ├── .eslintrc.base.js ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── .versionrc ├── CHANGELOG.md ├── README-zh_CN.md ├── README.md ├── index.android.js // Android entrance ├── index.ios.js // iOS portal ├── index.js // Android entrance(for compatibility) ├── package.json ├── rn-cli.config.js ├── src │ ├── api // A series of cloud APIs used in the project │ ├── components // Put the reusable functional components used in the project │ ├── composeLayout.tsx // Encapsulation processes some device events and device information needed inside the panel │ ├── config // Place some commonly used configuration files inside the panel │ ├── i18n // Place multi-language configuration files │ ├── main.tsx // The project entry file is inherited from the 'navigator layout'. Some necessary configurations, such as background and topbar, are passed in by rewriting the 'hookroute' method. The 'renderscape' method is overridden to control the route jump │ ├── models // Put some code related to Redux │ ├── pages // Places the components at each page level of the project │ ├── res // Put local resources, including pictures, SVG path, etc │ └── utils // Put some common tools and methods used to place the panel interior ├── tsconfig.json // TS configuration file └── yarn.lock

Introduction of core modules


Put a series of cloud APIs used in the project

Define API

import { TYSdk } from 'tuya-panel-kit'; // tips: TYSdk.apiRequest Generic support is provided to make the code more elegant~ export const someApiFn = () => { return TYSdk.apiRequest<any>('tuya.some.api.name', {}); };

Using the API

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


Place reusable functional components used in the project


Place some common configuration files inside the panel


Place multilingual configuration files. For specific redundant usage, please refer to Internationalization


Put some code related to redux, the internal common module encapsulates some commonly used states and actions;

Put some code related to redux, the internal common module encapsulates some commonly used States and actions;

  • dpState: DP point state of the current device;
    • Type definition: an object based on the function points of the current product;
    • How to obtain:
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> ); };
  • How to update:
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' })); // It can also be directly update DpState through the method in TYSdk.device // TYSdk.device.putDeviceData({ yourDpCode: 'yourDpValue' }); }; return ( <View> <Button text="Publish DP" onPress={handleClick} /> </View> ); };
  • devInfo: current device information;
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> ); };
  • How to set: devInfo information maintenance has been done in the basic template. It is not recommended that the business should be handled separately, so there is no excessive description.
  • logs: the report log information is issued by the DP point, which is only required by this project, so it is not described too much.


Place the components of each page level of the project, in which the following two pages are built-in in the project:

  • home: a console for debugging DP points, where consoleLayout is the log output component issued and reported by DP, and contentLayout is the component below the interactive control of DP;
  • setting: a most basic page, which is only used to show how to use routing and related basic configuration functions inside the project;


Place local resources, including images, SVG path, etc., which can be referenced by @res index.ts File, which we built in read.js File can be used to quickly traverse the new image file generation index.ts File export, the specific command can refer to the following example;


Some common tools and methods are used to place the panel interior;


The high-order functioncomposeLayout works in three ways:

During panel initialization,composeLayout processes the original devInfo and initializes the redux store.
When the panel is running,composeLayout monitors events related to device changes and updates the information to the corresponding redux store in real-time.
Associate the current component with the redux store through theconnect function.

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: the component that needs to be connected to the `redux store`. It is usually the main component. */ const composeLayout = (store, component) => { const NavigatorLayoutContainer = connect(_.identity)(component); const { dispatch } = store; /** * This function monitors the event of `device data change`. * When a DP's data is changed, it will synchronize the changed DP status to `redux`. * Similarly, when device information is changed, it will synchronize the changed device information to `redux`. */ TYEvent.on("deviceDataChange", (data) => { switch (data.type) { case "dpData": dispatch(responseUpdateDp(data.payload)); break; default: dispatch(deviceChange(data.payload)); break; } }); /** * This function monitors the event of `network status change`. * When device information is changed, it will synchronize the changed device information to `redux`. */ TYEvent.on("networkStateChange", (data) => { dispatch(deviceChange(data)); }); class PanelComponent extends Component { static propTypes = { // eslint-disable-next-line devInfo: PropTypes.object.isRequired, }; /** * If `devInfo` exists (usually it exists) when the panel enters, * This function will call `setDeviceInfo` to process the original `devInfo`, and then pass in `redux`. * * If `devInfo` does not exist when the panel enters, * This function will call `getDeviceInfo` to asynchronously acquire the processed `devInfo`, and then pass in `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;


To be brief, the entry componentMainLayout function only works in one way: It inherits fromNavigatorLayout, and helps manage multiple pages inside the panel.

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 }; // Use it with caution. Do not turn it on production. If the console printing level is too deep, it will cause performance problems // if (__DEV__) { // console.log('TYSdk :', TYSdk); // } class MainLayout extends NavigatorLayout<Props> { /** * * @desc hookRoute can do some control processing for specific routes here. For specific controllable parameters, please refer to [NavigationOptions](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/tuya-panel-kit/index.d.ts) type definition */ 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 * You can use the ID in the route to determine which component to use. * If there are extra props that need to be passed to page components, pass them here. * Note that the route parameter comes from the TYSdk.Navigator.push. * If you run TYSdk.Navigator.push ({ id: 'setting', title: 'Setting Page' }); * The routing stack is pushed, hookRoute and renderScape will receive route = { id: 'setting', title: 'setting page' }, * However, it should be noted that the route parameter of the home page is fixed as { id: 'main', initialRoute: true } * * @param {Object} route: route object. * @param {object} navigator: Navigator object. For more information, see 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);