Skip to content
Julian Knight edited this page Oct 1, 2019 · 23 revisions

NOTE: Needs updating for uibuilder v2. If you use REACT with uibuilder, please consider updating this article. Thanks.

Example: ReactJS

This is a quick introduction on how you can use Node-red, uibuilder and react all together.

Installation & Configuration

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
  • Add the "vue" example from the import 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.

  • npm install -g create-react-app This lets you create a complete REACT app and includes a suitable build step.

  • cd ~/.node-red/uibuilder/react

  • create-react-app myapp This creates a new sub-folder called myapp, we will be building the app in there.

  • Your app now needs access to the uibuilderfe.js file from the uibuilder package. You can copy it over manually but you would need to remember to do that whenever it is updated. Much better is to create a soft-link

    From: ~/.node-red/node_modules/node-red-contrib-uibuilder/nodes/src

    To: ~/.node-red/uibuilder/react/myapp/src/libs/uibuilder/

  • Edit the files listed below copy the code given here into the appropriate file.

  • npm build Assuming all goes well, your ready-to-use app will now exist in ~/.node-red/uibuilder/react/myapp/build

  • You now have several options. The quickest is to copy the contents of build to ~/.node-red/uibuilder/react/src

    NOTE: With this method, you have to alter the URL's in myapp/build/index.html after it has been built. That is to correct the resource urls. There are links to a stylesheet and two javascript resources, each must begin with ./. Let me know if you can work out a way to make this happen automatically.

  • You can now open the react_ui url (most easily done by opening the configuration editor of the uibuilder node and clicking on the link) - try sending a msg to it and you should see the information at the bottom of the page update.

The rest is up to you! See the VueJS examples to see how to use the different features of the uibuilder library.

myapp/public/index.html

myapp/src/App.js


NB: Below here is the original uibuilder v1 instructions - please remember that I don't use REACT, this comes from another user.

You can find a node-red-contrib-react template here

1. Install ReactJS & uibuilder using npm

Open a terminal/command prompt, cd to your node-red project

npm install node-red-contrib-uibuilder reactjs --save

2. Add reference for ReactJS to settings.js

Add the following to your ~/.node-red/settings.js file:

uibuilder: {
    userVendorPackages: ['reactjs'],
    debug: true
}

3. Init your uibuilder folder and create your reactjs project

  1. Create a uibuilder node name it react_ui and deploy (you can choose automatic creation of .html and .css files)
  2. 'cd uibuilder'
  3. mkdir src
  4. 'cd src'
  5. Install react in here (https://reactjs.org/tutorial/tutorial.html) npm install -g create-react-app && create-react-app my-app
  6. cd my-app
  7. IMPORTANT, in your react package file, add "hostpage":"/react_ui"
  8. In your setting file of node-red, add the following: uibuilder: { userVendorPackages: ['reactjs'], debug: true },

4. Create the socket connection React Component

/*Reactstuff*/
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { findDOMNode } from 'react-dom';

import uibuilder from '../../libs/uibuilder/uibuilderfe.js'

class UserData extends Component{
	constructor(props){
		super(props)

		this.state = {
			msg:'payload Hello World',
			UIBuilderVersion: '',
			webSocket : '',
			msgReceived : '',
			controlMsgReceived : '',
			msgSent : '',
			lastMsgReceived : '',
			lastCtlMsgReceived : '',
			lastMsgSent : ''
		}

		uibuilder.onChange('msg', (newVal) => {

			this.setState({
			  msg: newVal
			})
			this.forceUpdate();
			console.info("console.info: " + JSON.stringify(newVal))
		})


		uibuilder.onChange('msgsReceived',(newVal) =>{
			console.info('New msg sent to us from Node-RED over Socket.IO.TotalCount:',newVal)
			this.setState({
			  msgReceived: newVal
			})
			this.forceUpdate();
		})

		//IfSocket.IOconnects/disconnects
		uibuilder.onChange('ioConnected',(newVal) =>{
			console.info('Socket.IOConnectionStatusChanged:',newVal)
			this.setState({
			  webSocket: newVal
			})
			this.forceUpdate();
		})

		//IfamessageissentbacktoNode-RED
		uibuilder.onChange('msgsSent',(newVal) =>{
			console.info('New msg sent to Node-RED over Socket.IO.TotalCount:',newVal)
			this.setState({
			  msgSent: newVal
			})
			this.forceUpdate();
		})

		//IfwereceiveacontrolmessagefromNode-RED
		uibuilder.onChange('msgsCtrl',(newVal) =>{
			console.info('New control msg sent to us from Node-RED over Socket.IO.TotalCount:',newVal)
			this.setState({
			  controlMsgReceived: newVal
			})
			this.forceUpdate();
		})

	// 	//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"}}>
				<div>{'msg: ' + this.state.msg.payload}</div>
				<div>{'msg Received: ' + this.state.msgReceived}</div>
				<div>{'control MsgReceived: ' + this.state.controlMsgReceived}</div>
				<div>{'msg Sent: ' + this.state.msgSent}</div>
				<div>{'last Msg Received: ' + this.state.lastMsgReceived}</div>
				<div>{'last Ctl Msg Received: ' + this.state.lastCtlMsgReceived}</div>
				<div>{'last Msg Sent: ' + this.state.lastMsgSent}</div>

			</div>
		);

	}

	componentWillUnmount(){
		this.state.ui.destructor();
		this.state.ui=null;
	}

	shouldComponentUpdate(){
		//ascomponentisnotlinkedtotheexternaldata,thereisnoneedinupdates
		return false;
	}
}

export default UserData

5. Import the Component in your App.js

import UserData from './scenes/UserData'

class App extends Component {
  render() {
	return (
		<div className="App">
			<UserData title="User Data">
			</UserData>
		</div>
	);
  }
}

6. Overwrite your public/index.html with the following:

<!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</title>
  </head>
  <body>
	<div id="app">
		<h1>
			Welcome to REACT-UIbuilder for Node-RED!
		</h1>
	</div>
	<div id="root">
		<div id="app">
		</div>
	</div>
  </body>
</html>

7. Make a simlink for the build-dist folder

node-red-project/node_modules/node-red-contrib-uibuilder/nodes/src'-> src/libs/uibuilder/

8. Make a simlink for the uibuilder folder in the react project.

my-app/build -> 'Node-red-project/uibuilder/uibuilderNodeName/dist

You can use this post-script.js after the installation of your node-red project.

change this line to match your react folder name: const react_ui = new InstallReact("react_ui")

var fs = require('fs')
var process = require('process')

class InstallReact {
	constructor(uibuilderNodeName) {
		this.reactRelativePath = '\\uibuilder\\' + uibuilderNodeName + '\\src\\react_app\\'
		this.uibuilderDistRelativePath = '\\uibuilder\\' + uibuilderNodeName + '\\dist\\'
		this.uibuilderNodePath = '\\node_modules\\node-red-contrib-uibuilder\\nodes\\src\\'
		this.uibuilderFile = 'uibuilderfe.min.js'
	}

	createSymlink() {
	let err = "ok"
	console.log('TODO: Create symlink for uibuilderfe.min.js')
	console.log(process.cwd() + this.uibuilderNodePath)
	console.log(process.cwd() + this.reactRelativePath + 'libs/')

	fs.symlink(process.cwd() + this.uibuilderNodePath, process.cwd() + this.reactRelativePath + 'src/libs/uibuilder/', 'junction', function(err,stdout,stderr){
		console.log('err: ' + err)
		console.log('stdout: ' + stdout)
		console.log('stderr: ' + stderr)
		if (err == null){
			console.log('Symlink created')
		}
		})
	console.log('Create symlink for node-red dist folder')
	fs.symlink(process.cwd() + this.reactRelativePath + 'build/', process.cwd() + this.uibuilderDistRelativePath, 'junction', function(err,stdout,stderr){
		// console.log('err: ' + err)
		// console.log('stdout: ' + stdout)
		// console.log('stderr: ' + stderr)
		if (err == null){
			console.log('Symlink created')
		}
		})
	}

	installReact() {
		let stdout = "ok"

		var react = process.cwd() + this.reactRelativePath
		console.log('Installing ReactJS in cwd: ' + react);
		stdout = require('child_process').execSync('npm install', {cwd:react})
		if(stdout.status){
			console.log(stdout.status)
			process.exit()
		}
		stdout = require('child_process').execSync('npm run build', {cwd:react})
		if(stdout.status){
			console.log(stdout.status)
			process.exit()
		}
		return stdout
	}

	execute() {
		this.createSymlink()
		this.installReact()
	}
}

const react_ui = new InstallReact("react_ui")
react_ui.execute()
// const snw = new InstallReactAndNodered("snw");
// snw.execute()

console.log("Install Done")

Note [Important]

TODO Need to fix line 161 in uibuilderfe.js (uibuilderfe.min.js) For now, you can only comment the line manually... for the project to compile.

Clone this wiki locally