前言
大概花了三天時間看了下相關知識,在這先吧能看懂的跟大家聊一聊。
這是我在github上找的demo https://github.com/TuyaInc/tuya-panel-kit-template
以其中的examples\lampClassic為例子。
分析


接上篇分析main.js可以分析出啟動頁(首頁),下列為首頁代碼
import HomeBottomView from './bottom'; import Lamp from '../lamp'; const HomeScene = () => ( <View style={styles.container}> <Lamp /> <HomeBottomView /> </View> ); const styles = StyleSheet.create({ container: { flex: 1, }, }); export default HomeScene;
從上分析得由燈和底部按鈕組成。我們現在進入lamp目錄。以下是我了解的
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { View, StyleSheet, Image, TouchableWithoutFeedback } from 'react-native';
import { Utils, TYText } from 'tuya-panel-kit';
import { updateDp } from '../../redux/actions/common';
import { updateCloud } from '../../redux/actions/cloud';
import Config from '../../config';
import Strings from '../../i18n';
import LampInstance from '../../utils/LampInstance';
import { WORKMODE } from '../../utils/constant';
import { syncThrottle, handleFifthSceneColor } from '../../utils';
import Color from '../../utils/color';
import HuePicker from '../../components/HuePicker';
import resource from '../../res';
const { convertX: cx } = Utils.RatioUtils;
//React Native自行參考https://www.react-native.cn/docs/getting-started
class Lamp extends Component {
//先得知道React的State和Props是啥玩意
//propTypes:用來檢測props數據類型的變量,包括基本類型的的字符串,布爾值,數字,以及引用類型的對象,數組,函數,甚至還有ES6新增的符號類型
//isRequired表示必傳參數
static propTypes = {
power: PropTypes.bool.isRequired,
workMode: PropTypes.string.isRequired,
brightness: PropTypes.number.isRequired,
kelvin: PropTypes.number.isRequired,
colour: PropTypes.string.isRequired,
sceneValue: PropTypes.string.isRequired,
selectSceneColorIndex: PropTypes.number.isRequired,
isEditSceneColor: PropTypes.bool.isRequired,
isEditMode: PropTypes.bool.isRequired,
updateDp: PropTypes.func.isRequired,
selectSceneId: PropTypes.number.isRequired,
scenes: PropTypes.array.isRequired,
updateCloud: PropTypes.func.isRequired,
};
constructor(props) {
super(props);
//來自utils目錄猜測是調節燈光
LampInstance.setInstance(this);
//這玩意看不懂的參考這https://www.runoob.com/react/react-props.html(State 和 Props)
this.state = this.initData(this.props);
}
// 生命周期的方法有:
// componentWillMount 在渲染前調用,在客戶端也在服務端。
// componentDidMount : 在第一次渲染后調用,只在客戶端。之后組件已經生成了對應的DOM結構,可以通過this.getDOMNode()來進行訪問。
// 如果你想和其他JavaScript框架一起使用,可以在這個方法中調用setTimeout, setInterval或者發送AJAX請求等操作(防止異步操作阻塞UI)。
// componentWillReceiveProps 在組件接收到一個新的 prop (更新后)時被調用。這個方法在初始化render時不會被調用。
// shouldComponentUpdate 返回一個布爾值。在組件接收到新的props或者state時被調用。在初始化時或者使用forceUpdate時不被調用。
// 可以在你確認不需要更新組件時使用。
// componentWillUpdate在組件接收到新的props或者state但還沒有render時被調用。在初始化時不會被調用。
// componentDidUpdate 在組件完成更新后立即調用。在初始化時不會被調用。
// componentWillUnmount在組件從 DOM 中移除之前立刻被調用。
componentWillReceiveProps(nextProps) {
this.setState({
//在react中,會看到{...this.props}的代碼,不知道是什么意思,現在記錄一下。
//{...this.props}是props所提供的語法糖,可以將父組件的所有屬性復制給子組件
...this.initData(nextProps),
});
}
setLightColor(color, brightness) {
// 燈亮度效果由於1%-100%顯示比較差,對應顯示8%-100%范圍
this.shadowRef.setNativeProps({
style: { opacity: this.formatOpacity(brightness) },
});
this.ligthRef.setNativeProps({
style: { tintColor: color },
});
}
// 燈亮度效果由於1%-100%顯示比較差,對應顯示8%-100%范圍
formatOpacity(brightness) {
return 0.08 + ((brightness - 10) / (1000 - 10)) * (1 - 0.08);
}
initData(props) {
const {
workMode,
brightness,
kelvin,
colour,
sceneValue,
isEditSceneColor,
scenes,
selectSceneId,
selectSceneColorIndex,
} = props;
let currentColor = '#fff';
let currentBright = 1000;
let hsv = [0, 0, 0];
switch (workMode) {
case WORKMODE.WHITE:
currentColor = Color.brightKelvin2rgb(1000, kelvin);
currentBright = brightness;
break;
case WORKMODE.COLOUR:
hsv = Color.decodeColourData(colour);
currentColor = Color.hsv2hex(hsv[0], hsv[1], 1000);
currentBright = hsv[2];
break;
case WORKMODE.SCENE: {
let hsvbk;
if (isEditSceneColor) {
const exist = scenes.find(item => item.sceneId === selectSceneId);
if (exist) {
const [, , , ...hsvbks] = Color.decodeSceneValue(exist.value);
hsvbk = hsvbks[selectSceneColorIndex];
}
} else {
const [, , , ...hsvbks] = Color.decodeSceneValue(sceneValue);
[hsvbk] = hsvbks;
}
if (!hsvbk) {
hsvbk = [0, 0, 0, 0, 0];
}
hsv = hsvbk;
// 取第一組數據
const [h, s, v, b, k] = hsvbk;
// 白光
if (b || k) {
currentColor = Color.brightKelvin2rgb(1000, k);
currentBright = b;
} else {
currentColor = Color.hsv2hex(h, s, 1000);
currentBright = v;
}
break;
}
default:
break;
}
// 標題
const modeTitle = Strings.getLang(`mode_${workMode}`);
return {
modeTitle,
hsv,
currentColor,
currentBright,
};
}
handleChangePower = () => {
const { power } = this.props;
this.props.updateDp({
[Config.dpCodes.power]: !power,
});
};
handleHueChange = syncThrottle(
hue => {
const { hsv } = this.state;
const currentColor = Color.hsv2hex(hue, hsv[1], 1000);
this.setLightColor(currentColor, hsv[2]);
},
hue => {
const { hsv } = this.state;
const editHsv = [hue, hsv[1], hsv[2]];
const currentColor = Color.encodeColourControlData(...editHsv);
this.props.updateDp({
[Config.dpCodes.controlData]: currentColor,
});
}
);
hangleHueChangeCompelete = hue => {
this.handleHueChange.cancel();
const { isEditSceneColor, selectSceneId, scenes, selectSceneColorIndex } = this.props;
const { hsv } = this.state;
if (isEditSceneColor) {
const exist = scenes.find(item => item.sceneId === selectSceneId);
if (exist) {
const [num, speed, mode, ...hsvbks] = Color.decodeSceneValue(exist.value);
// 為了與v1版本一致,如果是第5個場景,則只顯示一個顏色,並根據用戶選擇了顏色處理成亮暗兩種顏色
const isFifth = num === 4;
if (selectSceneColorIndex < hsvbks.length) {
let newHsvbks = hsvbks;
if (isFifth) {
const [h, s, v] = hsvbks[0];
newHsvbks = handleFifthSceneColor(hue, s, v);
} else {
newHsvbks[selectSceneColorIndex][0] = hue;
}
const value = Color.encodeSceneValue([num, speed, mode, ...newHsvbks]);
this.props.updateDp({
[Config.dpCodes.sceneData]: value,
});
this.props.updateCloud(`scene_${+num}`, { sceneId: exist.sceneId, value });
}
}
} else {
this.props.updateDp({
[Config.dpCodes.colourData]: Color.encodeColourData(hue, hsv[1], hsv[2]),
});
}
this.setState({
hsv: [hue, hsv[1], hsv[2]],
});
};
//這塊是用來畫UI的,和觸發事件調用方法
render() {
const { power, isEditMode, isEditSceneColor, workMode } = this.props;
const { currentColor, currentBright, modeTitle } = this.state;
const isShowHue = power && isEditMode && (workMode === WORKMODE.COLOUR || isEditSceneColor);
const lampOnImage = resource.lightOn;
const lampOffImage = resource.lightOff;
return (
<View style={styles.container} accessibilityLabel="LampView">
{power && (
<TYText accessibilityLabel="Light_Mode_Name" style={[styles.title]}>
{modeTitle}
</TYText>
)}
<View style={styles.box}>
<Image
ref={ref => (this.shadowRef = ref)}
source={resource.lightShadow}
style={[
styles.lightShadow,
{ opacity: power ? this.formatOpacity(currentBright) : 0.2 },
]}
/>
<TYText style={[styles.powerTip, { opacity: power ? 0 : 1 }]}>
{Strings.getLang('power_tip')}
</TYText>
<HuePicker
style={[styles.huePicker, { opacity: isShowHue ? 1 : 0 }]}
hue={isShowHue ? this.state.hsv[0] : 0}
touchThumbRadius={cx(25)}
touchOffset={cx(8)}
onChange={this.handleHueChange}
onRelease={this.hangleHueChangeCompelete}
onPress={this.hangleHueChangeCompelete}
disabled={!isShowHue}
/>
<TouchableWithoutFeedback
onPress={this.handleChangePower}
accessibilityLabel="Light_Btn_Open"
>
<View style={styles.lightBtn}>
<Image
ref={ref => (this.ligthRef = ref)}
source={power ? lampOnImage : lampOffImage}
style={[
styles.light,
{ tintColor: power ? currentColor : 'rgba(255,255,255,0.4)' },
]}
/>
</View>
</TouchableWithoutFeedback>
</View>
</View>
);
}
}
//React Native 中用來集中定義組件的樣式
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
title: {
width: '100%',
position: 'absolute',
top: cx(10),
backgroundColor: 'transparent',
fontSize: cx(14),
textAlign: 'center',
},
box: {
width: cx(374),
height: cx(374),
alignItems: 'center',
justifyContent: 'center',
},
lightShadow: {
width: cx(283),
height: cx(284),
},
lightBtn: {
position: 'absolute',
width: cx(120),
height: cx(120),
top: cx(127),
left: cx(127),
zIndex: 1,
},
light: {
width: cx(120),
height: cx(120),
},
powerTip: {
position: 'absolute',
width: '100%',
bottom: cx(30),
left: 0,
textAlign: 'center',
fontSize: cx(12),
color: '#fff',
backgroundColor: 'transparent',
},
huePicker: {
position: 'absolute',
left: cx(49.5),
top: cx(49.5),
},
});
//React-Redux提供connect方法,用於從 UI 組件生成容器組件。connect的意思,就是將這兩種組件連起來。
export default connect(
({ dpState, cloudState }) => {
const {
dpCodes: {
power: powerCode,
workMode: workModeCode,
bright: brightCode,
kelvin: kelvinCode,
colourData: colourDataCode,
sceneData: sceneDataCode,
},
} = Config;
return {
power: dpState[powerCode],
workMode: dpState[workModeCode],
brightness: Reflect.has(dpState, brightCode) ? dpState[brightCode] : 1000,
kelvin: Reflect.has(dpState, kelvinCode) ? dpState[kelvinCode] : 1000,
colour: dpState[colourDataCode],
sceneValue: dpState[sceneDataCode],
isEditMode: cloudState.isEditMode,
isEditSceneColor: cloudState.isEditSceneColor,
selectSceneColorIndex: cloudState.selectSceneColorIndex,
selectSceneId: cloudState.selectSceneId,
scenes: cloudState.scenes,
};
},
dispatch => ({
updateDp: updateDp(dispatch),
updateCloud: updateCloud(dispatch),
})
)(Lamp);
大致知道了每個函數的用途,但實際使用還是無從下手。

