React Native中全局变量的动态变化

我的 React Native 应用程序中有一个 mqtt 客户端,它不断地从代理接收数据。这些数据在许多不同的屏幕/组件中的使用方式不同(我有 1 个类,它扩展每个屏幕的 React.Component)。例如,我在屏幕 1 上显示从主题 x 接收的数据,同时在屏幕 2 上显示从主题 y 和主题 x 接收的数据。


我存储这些数据的方式是使用 redux。所以我可以使用例如获取最新数据this.props.dataX。我不确定这是否是存储它的最佳方式。我想要实现的是显示该数据的动态列表,例如,第一个屏幕上的一个主题收到的数据的一个平面列表和主题2+主题1-屏幕2的另一个平面列表。


如果我只是将数据发送到平面列表,它不会变成动态的。我必须刷新页面才能呈现新数据:


<FlatList

    style={styles...}

    data={this.props.dataX}

    <renderItem={({item}) => <Item item={item}/>}

    keyExtractor={item => item.name}

/>

function Item({item}) {

    return (

        <View style={styles...}>

                <Text>{item.name}</Text>

                <Image style={styles.image} source={...getDeviceIcon(item.name)}/>

        </View>

    );

}

我知道如果这些数据处于组件的状态,那么它将是动态的。因此,尽管它实际上没有意义,但我尝试在状态中复制它,希望它是动态的。但它没有:


constructor(props) {

        super(props);

        this.state = {

            data: this.props.dataX

        };

}

那么我怎样才能实现这一目标呢?


眼眸繁星
浏览 69回答 3
3回答

千巷猫影

继续我的评论:这是我的做法的完整示例。我正在使用 mqttws31.js 库连接到蚊子。如果您需要,请告诉我。我有加载 redux 存储的 app.js 和 App.jsx 中的应用程序。App.jsx 处理我的 wsClient 函数,但您可以将它们移动到其他文件。这是重新渲染我的组件的 Redux Connect 函数和 mapstateToProps。如果 props 改变,组件会再次渲染商店.js:import { createStore } from 'redux'import { composeWithDevTools } from 'redux-devtools-extension';import { createReducer } from '@reduxjs/toolkit'; // I'm using the toolkit hereconst reducer = createReducer(initialState, {&nbsp; SET_ONE: (state, action) => {&nbsp; &nbsp; state.items[action.key] = action.value&nbsp; },&nbsp; SET_ALL: (state, action) => {&nbsp; &nbsp; state.items = action.data&nbsp; }})const initialState = {&nbsp; items: {}}const store = createStore(reducer,initialState);export default store;应用程序.js:import store from './store';import { Provider } from 'react-redux';import App from './app.jsx';window.addEventListener('load', (event) => {&nbsp; &nbsp; ReactDOM.render(&nbsp; &nbsp; &nbsp; &nbsp; <Provider store={store}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <App/>&nbsp; &nbsp; &nbsp; &nbsp; </Provider>,&nbsp; &nbsp; &nbsp; &nbsp; document.querySelector('#app-root')&nbsp; &nbsp; );});应用程序.jsx:import React from 'react';import store from './store';import '../vendor/paho-mqtt/mqttws31.js'; // the mqtt libconst MQTT = window.Paho.MQTT; // the MQTT objectclass App extends React.Component {&nbsp;&nbsp;&nbsp; &nbsp; state = {&nbsp; &nbsp; &nbsp; activeTab: 0,&nbsp; &nbsp; &nbsp; items: {}, //from redux&nbsp; &nbsp; &nbsp; wsClientStatus: 'Not Connected'&nbsp; &nbsp; }&nbsp; &nbsp; shouldComponentUpdate = (nextProps, nextState) => {&nbsp; &nbsp; &nbsp; const { wsClientStatus } = this.state&nbsp; &nbsp; &nbsp; if (wsClientStatus !== nextState.wsClientStatus) {&nbsp; &nbsp; &nbsp; &nbsp; return true&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; }&nbsp; &nbsp; componentDidMount = () => {&nbsp; &nbsp; &nbsp; &nbsp; this.wsClientInit();&nbsp; &nbsp; }&nbsp; &nbsp; render () {&nbsp; &nbsp; &nbsp; //console.log('app render')&nbsp; &nbsp; &nbsp; &nbsp; const { wsClientStatus } = this.state; // for a status bar&nbsp; &nbsp; &nbsp; &nbsp; const state = this.state&nbsp; &nbsp; &nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<DimmableLight topics={{DMX:{read:'DMX_0', write:'WEB/DMX_0'}}} bpTopic={"WEB/DI01"} location="WC" publish={this.wsClientPublish} />&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; wsClient = new MQTT.Client("YOUR HOST", 9001, "myclientid_" + parseInt(Math.random() * 100, 10));&nbsp; &nbsp; wsClientSetCallBacks = () => {&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; const that = this;&nbsp; &nbsp; &nbsp; this.wsClient.onConnectionLost = function (responseObject) {&nbsp; &nbsp; &nbsp; &nbsp; console.log("Ws client:: connexion lost...");&nbsp; &nbsp; &nbsp; &nbsp; that.setState({wsClientStatus: 'Not connected'});&nbsp; &nbsp; &nbsp; &nbsp; //reconnect&nbsp; &nbsp; &nbsp; &nbsp; that.wsClientConnect(that.wsClient);&nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; this.wsClient.onMessageArrived = function (message) {&nbsp; &nbsp; &nbsp; &nbsp; //Do something with the push message you received&nbsp; &nbsp; &nbsp; &nbsp; var data = JSON.parse(message.payloadString);&nbsp; &nbsp; &nbsp; &nbsp; console.log("Received <- " + message.destinationName + ":: ", data);&nbsp; &nbsp; &nbsp; &nbsp; //update the store&nbsp; &nbsp; &nbsp; &nbsp; //only one topic / all topics&nbsp; &nbsp; &nbsp; &nbsp; if (Object.keys(data).length > 1)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store.dispatch({type:'SET_ALL', data:data})&nbsp; &nbsp; &nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store.dispatch({type:'SET_ONE', key:Object.keys(data)[0], value:data[Object.keys(data)[0]]})&nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; wsClientInit = () => {&nbsp; &nbsp; &nbsp; &nbsp; this.wsClientSetCallBacks();&nbsp; &nbsp; &nbsp; &nbsp; this.wsClientConnect(this.wsClient);&nbsp; &nbsp; &nbsp; &nbsp; window.wsClientPublish = this.wsClientPublish; // to publish manualy within chrome console&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; wsClientConnect = (wsClient) => {&nbsp; &nbsp; &nbsp; const _this = this&nbsp; &nbsp; &nbsp; console.log("Ws client:: tentative de connexion...");&nbsp; &nbsp; &nbsp; _this.setState({wsClientStatus: 'Tentative de connexion'});&nbsp; &nbsp; &nbsp; wsClient.connect({&nbsp; &nbsp; &nbsp; &nbsp; timeout: 15,&nbsp; &nbsp; &nbsp; &nbsp; useSSL: true,&nbsp; &nbsp; &nbsp; &nbsp; userName: 'USER_NAME',&nbsp; &nbsp; &nbsp; &nbsp; password: 'USER_PASSWORD',&nbsp; &nbsp; &nbsp; &nbsp; //Gets Called if the connection has sucessfully been established&nbsp; &nbsp; &nbsp; &nbsp; onSuccess: function () {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log("Ws client:: Connecté.");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_this.setState({wsClientStatus: 'Connecté'});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;wsClient.subscribe('unipi_data/#', {qos: 0});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;wsClient.subscribe('WEB/#', {qos: 0});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;setTimeout(function() {this.wsClientPublish("getAllData", "unipi_system/data", 1);}, 1000);&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; //Gets Called if the connection could not be established&nbsp; &nbsp; &nbsp; &nbsp; onFailure: function (message) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log("Ws client:: La Connexion a échoué: " + message.errorMessage);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;setTimeout(function() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_this.wsClientConnect(wsClient);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}, 1000);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }&nbsp; &nbsp; wsClientPublish = (payload, topic, qos = 1) => {&nbsp; &nbsp; &nbsp; //Send your message (also possible to serialize it as JSON or protobuf or just use a string, no limitations)&nbsp; &nbsp; &nbsp; var message = new MQTT.Message(JSON.stringify(payload));&nbsp; &nbsp; &nbsp; message.destinationName = topic;&nbsp; &nbsp; &nbsp; message.qos = qos;&nbsp; &nbsp; &nbsp; this.wsClient.send(message);&nbsp; &nbsp; &nbsp; console.log("publish -> ", topic, payload, qos);&nbsp; &nbsp; }}export default App;就我而言,DimmableLight.jsx:import React from 'react';import { connect } from 'react-redux'; //connect child to the redux storeimport { withStyles } from '@material-ui/core/styles';import Card from '@material-ui/core/Card';import CardHeader from '@material-ui/core/CardHeader';import CardActions from '@material-ui/core/CardActions';import CardContent from '@material-ui/core/CardContent';import Typography from '@material-ui/core/Typography';import Slider from '@material-ui/core/Slider';import IconButton from '@material-ui/core/IconButton';import RadioButtonCheckedIcon from '@material-ui/icons/RadioButtonChecked';import Bulb from './Bulb' // an SVGclass DimmableLight extends React.Component {&nbsp; &nbsp; static defaultProps = {&nbsp; &nbsp; &nbsp; &nbsp; data: {},&nbsp; &nbsp; &nbsp; &nbsp; topics: {DMX:{read:'DMX_0', write:'WEB/DMX_0'}}, // override from props in App.jsx&nbsp; &nbsp; &nbsp; &nbsp; bpTopic: "WEB/DI01",&nbsp; &nbsp; &nbsp; &nbsp; location: 'Chambre'&nbsp; &nbsp; }&nbsp;&nbsp;&nbsp; &nbsp; state = {&nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; // IMPORTANT: update the component only when selected topics change&nbsp; &nbsp; shouldComponentUpdate = (nextProps, nextState) => {&nbsp; &nbsp; &nbsp; &nbsp; const { data } = this.props&nbsp; &nbsp; &nbsp; &nbsp; let shouldUpdate = false;&nbsp; &nbsp; &nbsp; &nbsp; data && Object.keys(data).map((key) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (data[key] !== nextProps.data[key])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; shouldUpdate = true&nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; return shouldUpdate;&nbsp; &nbsp; }&nbsp; &nbsp; handleChange = (evt, value) => {&nbsp; &nbsp; &nbsp; &nbsp; const { publish, topics } = this.props; // publish passed from props in App.jsx&nbsp; &nbsp; &nbsp; &nbsp; publish(parseInt(value), topics.DMX.write);&nbsp; &nbsp; }&nbsp; &nbsp; onBpPressed = (evt) => {&nbsp; &nbsp; &nbsp; &nbsp; const { publish, bpTopic } = this.props&nbsp; &nbsp; &nbsp; &nbsp; publish(parseInt(1), bpTopic);&nbsp; &nbsp; }&nbsp; &nbsp; onBpReleased = (evt) => {&nbsp; &nbsp; &nbsp; &nbsp; const { publish, bpTopic } = this.props&nbsp; &nbsp; &nbsp; &nbsp; publish(parseInt(0), bpTopic);&nbsp; &nbsp; }&nbsp; &nbsp; render () {&nbsp; &nbsp; &nbsp; &nbsp; const { data, topics, location, classes } = this.props&nbsp; &nbsp; &nbsp; &nbsp; //console.log('render dimmable', location)&nbsp; &nbsp; &nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Card className={classes.root}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <CardHeader title={location}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </CardHeader>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <CardContent className={classes.cardContent}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Bulb luminosity={(data[topics.DMX.read] || 0)/254}/>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </CardContent>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <CardActions className={classes.cardActions}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Slider min={0} max={254} value={data[topics.DMX.read] || 0} onChange={this.handleChange} aria-labelledby="continuous-slider" />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <IconButton color="primary" variant="contained" onMouseDown={this.onBpPressed} onMouseUp={this.onBpReleased}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <RadioButtonCheckedIcon/>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </IconButton>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </CardActions>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </Card>&nbsp; &nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; }}const styles = theme => ({&nbsp; &nbsp; root: {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; [theme.breakpoints.down('sm')]: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; minWidth: '100%',&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxWidth: '100%',&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; &nbsp; &nbsp; [theme.breakpoints.up('sm')]: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; minWidth: 180,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxWidth: 180,&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; },&nbsp; &nbsp; cardContent: {&nbsp; &nbsp; &nbsp; &nbsp; textAlign: 'center'&nbsp; &nbsp; },&nbsp; &nbsp; cardActions: {&nbsp; &nbsp; &nbsp; &nbsp; margin: '0px 10px 0px 10px',&nbsp; &nbsp; &nbsp; &nbsp; '& > :first-child': {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; margin: '0 auto'&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; });// Connect only wanted topics, set first in defaultProps to be sure to have them in ownPropsconst mapStateToProps = (state, ownProps) => {&nbsp; &nbsp; let data = []&nbsp; &nbsp; Object.keys(ownProps.topics).map(topicKey => {&nbsp; &nbsp; &nbsp; &nbsp; data[ownProps.topics[topicKey].read] = state.items[ownProps.topics[topicKey].read] || 0&nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; return {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: data&nbsp; &nbsp; &nbsp; }}&nbsp;&nbsp;export default connect(mapStateToProps)(withStyles(styles, {withTheme: true})(DimmableLight))

动漫人物

该遮阳篷符合您的要求:应该可以工作,但未经测试。import React from 'react';import { connect } from 'react-redux'; // to re-render the componentclass myFlatList extends React.Component {&nbsp; static defaultProps = {&nbsp; &nbsp; data: []&nbsp; &nbsp; topics: ['dataX'] // ['dataX', 'dataY'] for screen 2&nbsp; }&nbsp; Item = ({item}) => {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; &nbsp; <View style={styles...}>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Text>{item.name}</Text>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <Image style={styles.image} source={...getDeviceIcon(item.name)}/>&nbsp; &nbsp; &nbsp; &nbsp; </View>&nbsp; &nbsp; );&nbsp; }&nbsp; render () {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp;<FlatList&nbsp; &nbsp; &nbsp; &nbsp;style={styles...}&nbsp; &nbsp; &nbsp; &nbsp;data={this.props.data['dataX']}&nbsp; &nbsp; &nbsp; &nbsp;<renderItem={({item}) => <Item item={item}/>}&nbsp; &nbsp; &nbsp; &nbsp;keyExtractor={item => item.name}&nbsp; &nbsp; &nbsp;/>&nbsp; &nbsp; )&nbsp; }}mapStateToProps = (state, ownProps) => {&nbsp; let Data;&nbsp; ownProps.topics.map(topicKey => {&nbsp; &nbsp; &nbsp; &nbsp; data[topicKey] = state.items[topicKey] || "" //empty string if state not ready&nbsp; });&nbsp; return {&nbsp; &nbsp; &nbsp;data: data&nbsp; }}export connect(mapStateToProps)(myFlatList);

跃然一笑

尝试将数据道具/状态添加到 FlatList 的 extraData 道具中,每次数据发生变化时列表都应该重新渲染。<FlatListstyle={styles...}data={this.props.dataX}extraData={this.props.dataX} //OR this.state.data<renderItem={({item}) => <Item item={item}/>}keyExtractor={item => item.name}/>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript