为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

眼眸繁星 2023-12-14 14:38:30
我的 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        };}那么我怎样才能实现这一目标呢?
查看完整描述

3 回答

?
千巷猫影

TA贡献1829条经验 获得超7个赞

继续我的评论:这是我的做法的完整示例。


我正在使用 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 here


const reducer = createReducer(initialState, {

  SET_ONE: (state, action) => {

    state.items[action.key] = action.value

  },

  SET_ALL: (state, action) => {

    state.items = action.data

  }

})


const initialState = {

  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) => {

    ReactDOM.render(

        <Provider store={store}>

            <App/>

        </Provider>,

        document.querySelector('#app-root')

    );

});

应用程序.jsx:


import React from 'react';

import store from './store';

import '../vendor/paho-mqtt/mqttws31.js'; // the mqtt lib

const MQTT = window.Paho.MQTT; // the MQTT object


class App extends React.Component {

  

    state = {

      activeTab: 0,

      items: {}, //from redux

      wsClientStatus: 'Not Connected'

    }


    shouldComponentUpdate = (nextProps, nextState) => {

      const { wsClientStatus } = this.state

      if (wsClientStatus !== nextState.wsClientStatus) {

        return true

      }

      return false;

    }



    componentDidMount = () => {

        this.wsClientInit();

    }



    render () {

      //console.log('app render')

        const { wsClientStatus } = this.state; // for a status bar

        const state = this.state

        return (

           <DimmableLight topics={{DMX:{read:'DMX_0', write:'WEB/DMX_0'}}} bpTopic={"WEB/DI01"} location="WC" publish={this.wsClientPublish} />

        )

    }

   

    wsClient = new MQTT.Client("YOUR HOST", 9001, "myclientid_" + parseInt(Math.random() * 100, 10));


    wsClientSetCallBacks = () => {

      

      const that = this;

      this.wsClient.onConnectionLost = function (responseObject) {

        console.log("Ws client:: connexion lost...");

        that.setState({wsClientStatus: 'Not connected'});

        //reconnect

        that.wsClientConnect(that.wsClient);

      };


      this.wsClient.onMessageArrived = function (message) {

        //Do something with the push message you received

        var data = JSON.parse(message.payloadString);

        console.log("Received <- " + message.destinationName + ":: ", data);


        //update the store

        //only one topic / all topics

        if (Object.keys(data).length > 1)

          store.dispatch({type:'SET_ALL', data:data})

        else

          store.dispatch({type:'SET_ONE', key:Object.keys(data)[0], value:data[Object.keys(data)[0]]})

      };

    }

        

    wsClientInit = () => {

        this.wsClientSetCallBacks();

        this.wsClientConnect(this.wsClient);

        window.wsClientPublish = this.wsClientPublish; // to publish manualy within chrome console

    }

   

    wsClientConnect = (wsClient) => {

      const _this = this

      console.log("Ws client:: tentative de connexion...");

      _this.setState({wsClientStatus: 'Tentative de connexion'});

      wsClient.connect({

        timeout: 15,

        useSSL: true,

        userName: 'USER_NAME',

        password: 'USER_PASSWORD',

        //Gets Called if the connection has sucessfully been established

        onSuccess: function () {

          console.log("Ws client:: Connecté.");

         _this.setState({wsClientStatus: 'Connecté'});

         wsClient.subscribe('unipi_data/#', {qos: 0});

         wsClient.subscribe('WEB/#', {qos: 0});

         setTimeout(function() {this.wsClientPublish("getAllData", "unipi_system/data", 1);}, 1000);

        },

        //Gets Called if the connection could not be established

        onFailure: function (message) {

          console.log("Ws client:: La Connexion a échoué: " + message.errorMessage);

         setTimeout(function() {

           _this.wsClientConnect(wsClient);

         }, 1000);

        }

      });

    }


    wsClientPublish = (payload, topic, qos = 1) => {

      //Send your message (also possible to serialize it as JSON or protobuf or just use a string, no limitations)

      var message = new MQTT.Message(JSON.stringify(payload));

      message.destinationName = topic;

      message.qos = qos;

      this.wsClient.send(message);

      console.log("publish -> ", topic, payload, qos);

    }

}


export default App;

就我而言,DimmableLight.jsx:


import React from 'react';

import { connect } from 'react-redux'; //connect child to the redux store

import { 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 SVG



class DimmableLight extends React.Component {

    static defaultProps = {

        data: {},

        topics: {DMX:{read:'DMX_0', write:'WEB/DMX_0'}}, // override from props in App.jsx

        bpTopic: "WEB/DI01",

        location: 'Chambre'

    }

  

    state = {


    } 



    // IMPORTANT: update the component only when selected topics change

    shouldComponentUpdate = (nextProps, nextState) => {

        const { data } = this.props

        let shouldUpdate = false;

        data && Object.keys(data).map((key) => {

            if (data[key] !== nextProps.data[key])

                shouldUpdate = true

        })

        return shouldUpdate;

    }


    handleChange = (evt, value) => {

        const { publish, topics } = this.props; // publish passed from props in App.jsx

        publish(parseInt(value), topics.DMX.write);

    }


    onBpPressed = (evt) => {

        const { publish, bpTopic } = this.props

        publish(parseInt(1), bpTopic);

    }


    onBpReleased = (evt) => {

        const { publish, bpTopic } = this.props

        publish(parseInt(0), bpTopic);

    }



    render () {

        const { data, topics, location, classes } = this.props

        //console.log('render dimmable', location)

        return (

            <Card className={classes.root}>

                <CardHeader title={location}>

                </CardHeader>

                <CardContent className={classes.cardContent}>

                    <Bulb luminosity={(data[topics.DMX.read] || 0)/254}/>

                </CardContent>

                <CardActions className={classes.cardActions}>

                    <Slider min={0} max={254} value={data[topics.DMX.read] || 0} onChange={this.handleChange} aria-labelledby="continuous-slider" />

                    <IconButton color="primary" variant="contained" onMouseDown={this.onBpPressed} onMouseUp={this.onBpReleased}>

                        <RadioButtonCheckedIcon/>

                    </IconButton>

                </CardActions>

            </Card>

        )

    }


}




const styles = theme => ({

    root: { 

        [theme.breakpoints.down('sm')]: {

            minWidth: '100%',

            maxWidth: '100%',

        },

        [theme.breakpoints.up('sm')]: {

            minWidth: 180,

            maxWidth: 180,

        },

    },

    cardContent: {

        textAlign: 'center'

    },

    cardActions: {

        margin: '0px 10px 0px 10px',

        '& > :first-child': {

            margin: '0 auto'

        }

    }

    

  });



// Connect only wanted topics, set first in defaultProps to be sure to have them in ownProps

const mapStateToProps = (state, ownProps) => {

    let data = []

    Object.keys(ownProps.topics).map(topicKey => {

        data[ownProps.topics[topicKey].read] = state.items[ownProps.topics[topicKey].read] || 0

    });

      return {

          data: data

      }

}  


export default connect(mapStateToProps)(withStyles(styles, {withTheme: true})(DimmableLight))



查看完整回答
反对 回复 2023-12-14
?
动漫人物

TA贡献1815条经验 获得超10个赞

该遮阳篷符合您的要求:应该可以工作,但未经测试。


import React from 'react';

import { connect } from 'react-redux'; // to re-render the component


class myFlatList extends React.Component {

  static defaultProps = {

    data: []

    topics: ['dataX'] // ['dataX', 'dataY'] for screen 2

  }


  Item = ({item}) => {

    return (

        <View style={styles...}>

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

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

        </View>

    );

  }


  render () {

    return (

     <FlatList

       style={styles...}

       data={this.props.data['dataX']}

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

       keyExtractor={item => item.name}

     />

    )

  }


}


mapStateToProps = (state, ownProps) => {

  let Data;

  ownProps.topics.map(topicKey => {

        data[topicKey] = state.items[topicKey] || "" //empty string if state not ready

  });

  return {

     data: data

  }

}


export connect(mapStateToProps)(myFlatList);


查看完整回答
反对 回复 2023-12-14
?
跃然一笑

TA贡献1826条经验 获得超6个赞

尝试将数据道具/状态添加到 FlatList 的 extraData 道具中,每次数据发生变化时列表都应该重新渲染。


<FlatList

style={styles...}

data={this.props.dataX}

extraData={this.props.dataX} //OR this.state.data

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

keyExtractor={item => item.name}

/>


查看完整回答
反对 回复 2023-12-14
  • 3 回答
  • 0 关注
  • 142 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信