- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 93
Example: ReactJS
This is a quick introduction on how you can use Node-red, uibuilder and react all together.
NOTE 2022-12-21:
Please see both the updated version of this at github.com/gaillarddamien/uibuilder-react-example AND also the issues raised on Issue #2 on that repo (unless the repo has been updated).
Also see the ReactJS example with no build step required on this WIKI.
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 dev dependency
npm install ../../node_modules/node-red-contrib-uibuilder --save-dev# 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/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 UserDatanpm run buildThis 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 startApp 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)