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))
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);
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}
/>
添加回答
举报