-
-
Notifications
You must be signed in to change notification settings - Fork 85
Example: ReactJS
This is a quick introduction on how you can use Node-red, uibuilder and react all together.
NB: I will assume that you are using Linux and have installed Node-RED in the default way (globally). I also assume that your <userDir>
folder is in the default location (~/.node-red
) and that you are not using projects. Adjust the example paths if some of that isn't true.
- Install uibuilder from the Node-RED palette menu.
- Change the name and URL in the resulting node to something helpful to you - this example will use the URL
react_ui
. - Under "Advanced Settings", turn off "Copy index ...." because we won't be using those files.
- Deploy.
- Use uibuilder's library manager to install
reactjs
.
Unfortunately, REACT is too complex to allow everything to be done from within the Node-RED Editor. So from here, you need a terminal session on your server so that you can run command lines.
cd ~/.node-red/uibuilder
# create a new react app, using the default template (see https://github.com/facebook/create-react-app for details)
npx create-react-app react_ui
cd react_ui
# install node-red-contrib-uibuilder as a local/relative dependency
npm install ../../node_modules/node-red-contrib-uibuilder --save
# see https://create-react-app.dev/docs/advanced-configuration/ for details
PUBLIC_URL=.
BUILD_PATH=./dist
BROWSER=none
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React UI - uibuilder and Node-RED</title>
</head>
<body>
<div>
<h1>
Welcome to REACT-UIbuilder for Node-RED!
</h1>
</div>
<div id="root">
<div id="app">
</div>
</div>
</body>
</html>
import React from 'react';
import './App.css';
// Import uibuilder enabled component
import UserData from './scenes/UserData';
function App() {
return (
<div className="App">
{/* THIS IS THE UIBUILDER COMPONENT */}
<UserData title="User Data"></UserData>
</div>
);
}
export default App;
body {
margin: 1rem;
padding: 1rem;
}
.d1 {
margin: 0.5rem;
padding: 0.5rem;
}
/* This is where the uibuilder action happens */
import React, {Component} from 'react';
//import ReactDOM from 'react-dom';
//import { findDOMNode } from 'react-dom';
import uibuilder from 'node-red-contrib-uibuilder/front-end/src/uibuilderfe'
class UserData extends Component {
constructor(props) {
super(props)
/** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3
* Pass the namespace and ioPath variables if hosting page is not in the instance root folder
* e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.
* e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names
*/
uibuilder.start();
this.state = {
// Example of retrieving data from uibuilder
feVersion: uibuilder.get('version'),
socketConnectedState: false,
serverTimeOffset: '[unknown]',
msgRecvd: '[Nothing]',
msgsReceived: 0,
msgCtrl: '[Nothing]',
msgsControl: 0,
msgSent: '[Nothing]',
msgsSent: 0,
msgCtrlSent: '[Nothing]',
msgsCtrlSent: 0,
}
/** You can use the following to help trace how messages flow back and forth.
* You can then amend this processing to suite your requirements.
*/
//#region ---- Trace Received Messages ---- //
// If msg changes - msg is updated when a standard msg is received from Node-RED over Socket.IO
// newVal relates to the attribute being listened to.
uibuilder.onChange('msg', (newVal) => {
this.setState({'msgRecvd': newVal});
console.info('[uibuilder.onChange] msg received from Node-RED server:', newVal);
})
// As we receive new messages, we get an updated count as well
uibuilder.onChange('msgsReceived', (newVal) => {
console.info('[uibuilder.onChange] Updated count of received msgs:', newVal);
this.setState({'msgsReceived': newVal});
})
// If we receive a control message from Node-RED, we can get the new data here - we pass it to a Vue variable
uibuilder.onChange('ctrlMsg', (newVal) => {
console.info('[uibuilder.onChange:ctrlMsg] CONTROL msg received from Node-RED server:', newVal);
this.setState({'msgCtrl': newVal});
})
// Updated count of control messages received
uibuilder.onChange('msgsCtrl', (newVal) => {
console.info('[uibuilder.onChange:msgsCtrl] Updated count of received CONTROL msgs:', newVal);
this.setState({'msgsControl': newVal});
})
//#endregion ---- End of Trace Received Messages ---- //
//#region ---- Trace Sent Messages ---- //
// You probably only need these to help you understand the order of processing //
// If a message is sent back to Node-RED, we can grab a copy here if we want to
uibuilder.onChange('sentMsg', (newVal) => {
console.info('[uibuilder.onChange:sentMsg] msg sent to Node-RED server:', newVal);
this.setState({'msgSent': newVal});
})
// Updated count of sent messages
uibuilder.onChange('msgsSent', (newVal) => {
console.info('[uibuilder.onChange:msgsSent] Updated count of msgs sent:', newVal);
this.setState({'msgsSent': newVal});
})
// If we send a control message to Node-RED, we can get a copy of it here
uibuilder.onChange('sentCtrlMsg', (newVal) => {
console.info('[uibuilder.onChange:sentCtrlMsg] Control message sent to Node-RED server:', newVal);
this.setState({'msgCtrlSent': newVal});
})
// And we can get an updated count
uibuilder.onChange('msgsSentCtrl', (newVal) => {
console.info('[uibuilder.onChange:msgsSentCtrl] Updated count of CONTROL msgs sent:', newVal);
this.setState({'msgsCtrlSent': newVal});
})
//#endregion ---- End of Trace Sent Messages ---- //
// If Socket.IO connects/disconnects, we get true/false here
uibuilder.onChange('ioConnected', (newVal) => {
console.info('[uibuilder.onChange:ioConnected] Socket.IO Connection Status Changed to:', newVal)
this.setState({'socketConnectedState': newVal})
})
// If Server Time Offset changes
uibuilder.onChange('serverTimeOffset', (newVal) => {
console.info('[uibuilder.onChange:serverTimeOffset] Offset of time between the browser and the server has changed to:', newVal)
this.setState({'serverTimeOffset': newVal})
})
//Manually send a message back to Node-RED after 2 seconds
window.setTimeout(function () {
console.info('Sending a message back to Node-RED-after2sdelay')
uibuilder.send({'topic': 'uibuilderfe', 'payload': 'I am a message sent from the uibuilder front end'})
}, 2000)
}
render() {
return (
<div ref="root" style={{height: "50vh"}}>
<hr></hr>
<div className="d1">
<div>Last msg Received:</div>
<pre><code>{JSON.stringify(this.state.msgRecvd, null, 2)}</code></pre>
<div># Msgs Received: {this.state.msgsReceived}</div>
</div>
<div className="d1">
<div>last Ctl Msg Received:</div>
<pre><code>{JSON.stringify(this.state.msgCtrl, null, 2)}</code></pre>
<div># Control Msgs Received: {this.state.msgsControl}</div>
</div>
<div className="d1">
<div>last Msg Sent</div>
<pre><code>{JSON.stringify(this.state.msgSent, null, 2)}</code></pre>
<div># msgs Sent: {this.state.msgsSent}</div>
</div>
<div className="d1">
<div>Socket Connected?: {this.state.socketConnectedState}</div>
<div>uibuilderfe Version: {this.state.feVersion}</div>
<div>Server Time Offset from browser: {this.state.serverTimeOffset}</div>
</div>
</div>
);
}
}
export default UserData
npm run build
This will produce a production build under ./dist
.
You can now browse http://localhost:1880/react_ui
Add the following line
{
...
"proxy": "http://localhost:1880"
...
}
npm run start
App is now available at http://localhost:3000/react_ui
NOTE: This example was built on top of the former version of this wiki page, and I assumed it should remain as close as possible from the original submission. I have also produced a FP (functional programming) version of it, as well as a TypeScript version. Please see branches of https://github.com/gaillarddamien/uibuilder-react-example if you're interested.
Please feel free to add comments to the page (clearly mark with your initials & please add a commit msg so we know what has changed). You can contact me in the Discourse forum, or raise an issue here in GitHub! I will make sure all comments & suggestions are represented here.
-
Walkthrough 🔗 Getting started
-
In Progress and To Do 🔗 What's coming up for uibuilder?
-
Awesome uibuilder Examples, tutorials, templates and references.
-
How To
- How to send data when a client connects or reloads the page
- Send messages to a specific client
- Cache & Replay Messages
- Cache without a helper node
- Use webpack to optimise front-end libraries and code
- How to contribute & coding standards
- How to use NGINX as a proxy for Node-RED
- How to manage packages manually
- How to upload a file from the browser to Node-RED
-
Vanilla HTML/JavaScript examples
-
VueJS general hints, tips and examples
- Load Vue (v2 or v3) components without a build step (modern browsers only)
- How to use webpack with VueJS (or other frameworks)
- Awesome VueJS - Tips, info & libraries for working with Vue
- Components that work
-
VueJS v3 hints, tips and examples
-
VueJS v2 hints, tips and examples
- Dynamically load .vue files without a build step (Vue v2)
- Really Simple Example (Quote of the Day)
- Example charts using Chartkick, Chart.js, Google
- Example Gauge using vue-svg-gauge
- Example charts using ApexCharts
- Example chart using Vue-ECharts
- Example: debug messages using uibuilder & Vue
- Example: knob/gauge widget for uibuilder & Vue
- Example: Embedded video player using VideoJS
- Simple Button Acknowledgement Example Thanks to ringmybell
- Using Vue-Router without a build step Thanks to AFelix
- Vue Canvas Knob Component Thanks to Klaus Zerbe
-
Examples for other frameworks (check version before trying)
- Basic jQuery example - Updated for uibuilder v6.1
- ReactJS with no build - updated for uibuilder v5/6
-
Examples for other frameworks (may not work, out-of-date)
-
Outdated Pages (Historic only)
- v1 Examples (these need updating to uibuilder v2/v3/v4/v5)