Getting started with uibuilder and React?

Hi,

I'm planning to build my own interface in uibuilder using React, however I'm having trouble finding any documentation or guides to do this.

Does anyone know where to start with marrying React and uibuilder? I haven't used either very much in the past.

Thanks

There is an example in the repository

I've taken a look at this, it says at the top that it needs updated and I haven't been able to get it to work regardless.

Hi, sorry yes, while I managed to get REACT working using the previous version of uibuilder, I've not had time to update it and I don't generally use REACT. Let's see if we can't get you somewhere anyway ... Let me look up the entry in the WIKI and see if I can at least give you some clues so you can get started. Back in a tick.

Agrh! Now I remember why I gave up on REACT!

This will take me longer to do that it will probably take you to fix so let me explain and hopefully that will be enough to get you going.

Before I do though, are you sure you want to use REACT? Because I can tell you it is much more complex to get started with than VueJS is even putting aside uibuilder.

Well anyway, here is what you need:

  • 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

  • deploy

  • Use uibuilder's library manager to install reactjs. Actually, you can skip this for now if you like and use REACT direct from CDN

  • Edit index.html using uibuilder's source code editor and replace the VueJS example with a simple REACT example such as the one in the link above. Make sure that works.

  • Add the uibuilderfe library to index.html library by including the following link:

    <script src="./uibuilderfe.min.js"></script>
    
  • In your JavaScript code, you need to insert uibuilder.start() somewhere that will be triggered once REACT is loaded and running.

Finally, you will want to create a function that listens for incoming messages from Node-RED, you can do that with the following example. I think it should go just below wherever you put uibuilder.start().

uibuilder.onChange('msg', function(msg){
    console.log('[uibuilder.onChange] Updated count of received msgs:', msg)
})

Once all of that is working, you can play with the code and see how uibuilder works.

Once you understand the basics, the next step would be to configure a build step because REACT examples very rarely come without needing one. So configure webpack or similar in the root folder for your node instance.

That is to say, if you have installed Node-RED the normal way and on Linux & if you are not using Node-RED projects and have given uibuilder a URL of reactjs, then you will need access to your servers filing system at ~/.node-red/uibuilder/reactjs. That folder contains 2 sub-folders dist and src. Your front-end code as discussed above should be in the src folder. Configure webpack to build into the dist folder & configure it for REACT. Then you can use a more standard REACT example such as the one in the WIKI, run your build and everything should just work since uibuilder should now ignore the src folder and load everything from the dist folder automatically.

Hoping this makes some sense?

If so and you get things working, I'd love to get a copy of your code and webpack configuration so that I can create a workable WIKI entry.

OK, I don't think that I understand why but I think I can update the WIKI example enough so that you can at least get it working. I'll update here when I've done that.

OK, the WIKI example for REACT is updated for v2 - though I have to say that I clearly don't understand REACT very well because not everything is working as I'd expect it to. However, I think that it is enough to get people going.

1 Like

This is brilliant.

One question (despite making myself out to be a complete amateur), how do I create the environment variable 'PUBLIC_URL'? I've managed to follow all the steps up until that point.

(I'm using ubuntu, if that's relevant at all.)

Thanks!

There are various ways of doing that, google for
set environment variable ubuntu
and no doubt you will find it.

Ok, I've followed the tutorial, ran 'npm run build' and it looks like it works however the build folder doesn't exist.

The only notable thing in the log is

'./src/scenes/UserData.js
Line 167: Do not mutate directly. Use setState() react/no-direct-mutation-state'

Sorry, I didn't put that in the WIKI because I ran out of time and energy! As Colin says, this is dependent on your OS. Indeed, on Windows it even differs if you are using PowerShell instead of the cmd prompt.

Ah, drat - that was left in from the person who originally gave me the code, I think that REACT has gone through several updates since then and you can now no longer directly change a state variable, you have to use setState instead.

So the following:

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

Should be: ...

Urm, actually, I don't know what it should be to be honest. You will need to understand more about REACT I'm afraid. Sorry, I really don't understand REACT any more, it seems as bad as Angular now for being overly complex.

Try commenting out the whole of the componentWillUnmount function?


Did I say that VueJS was a LOT easier to get started with?

I've gotten uibuilder to work with React. Here is a dump of my notes on getting it setup:
- Create new react app: https://facebook.github.io/create-react-app/docs/getting-started, https://reactjs.org/docs/create-a-new-react-app.html
○ go to ~/.node-red/uibuilder/react_ui/src
§ delete the "react_app" folder with all its subfolders (otherwise you'll have conflicting files)
§ create your react app here called "react_app"
npx create-react-app react_app
□ note: do not use sudo with this command
- Create symlink from react build folder to uibuilder's "dist" folder - here's how
○ Compile first: run "npm run build" first to create the build folder in react_app
§ To compile, I needed to do this from : https://github.com/babel/babel/issues/8599
npm install -D babel-loader @babel/core @babel/preset-env
○ Delete the current uibuilder dist directory "rm -r blabla"
○ Create a symlink where the dist was by running (for example):
ln -s '/home/alphaori/.node-red/uibuilder/react_ui/src/react_app/build' '/home/alphaori/.node-red/uibuilder/react_ui/dist'
- Compile react app
○ Go to react_ui/src/react_app/src and run
npm run build

Replace my username with yours.

Thanks for sharing that. I don't suppose you fancy putting that into a WIKI page?

It would make a handy addition to the uibuilder WIKI.

1 Like

Ok, I'd be glad to do that. However, I'm still using uibuilder v1 so I think that I'll wait until I've upgraded to v2 (hopefully soon) and then update my notes for more general use.

1 Like

Thanks for the detailed instructions. But.. unfortunately, I am getting into some trouble
Getting a blank screen with the following errors. can you please help

This is because you have outdated HTML when trying to load your resources. That means that Node-RED's ExpressJS server has misinterpreted the file type to be served and has send them as default HMTL instead of CSS or JavaScript resources. This used to work on older browsers but doesn't any longer.

For CSS, either use:

<link rel="stylesheet" href="./index.css" media="all">

or

<link type="text/css" rel="stylesheet" href="../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css" />

For JavaScript, use:

<script src="./index.js"></script>
1 Like

Thank you. I added the directory to the static in config.js file and that also worked. But.. sure this is a better solution. I will do this way

1 Like

Hi,
Stated another clean VM to try it out. The (auto) created HTML page is in fact having the same code you mentioned and still it is giving issues.

The only way I am able to fix it right now is by adding that directory to the static in config.js in .node-red directory.

Site suggests me to create a "PUBLIC_URL=." env variable. I tried that too. Didn't work.
Please let me know if there is a better way to resolve this issue

So if you create a new flow with an inject/uibuilder/debug node flow, you are saying that it doesn't work?

Which directory?

The dist directory to the static. But.. now.. I am able to make it work without that. I didn't change anything but.. it is working. Still trying to find what got fixed.
Thanks for all your help.

On the other hand, I am trying to set the msg._socketId to send message back from frontend to the back end to a specific instance. Anyone has a working example for this?

The dist folder is ignored by uibuilder unless you have an index.html file in it. If you do, then the src folder is ignored instead. At one point I did have both folders served but that caused issues from time-to-time. So if you are serving up your app from the src folder, your other resources should go in that same folder, similarly if you've used a build step and are using the dist folder, put your resource files there. You could keep things simple by putting everything in the src folder and use your build step not only to "compile" the js/css but also to copy the required resources to the dist folder as well. That would further let you do things like run auto-optimisation on assets & create checksums for security & caching.

You need to use the control msgs from uibuilder to capture the socket id whenever a client connects AND when a client reloads (as that resets the id). Then, if you want to send a msg to a specific client, you add that socket id onto the msg. If your flow is acting on a data msg coming out of uibuilder, that also has the socket id so you can use that.

Just remember that there are several things that can trigger a change to the socket id, this is not under uibuilder or Node-RED's control I'm afraid.

The next major release of uibuilder will have some integrated authentication and authorisation capabilities and you will be able to use that to provide a more stable identifier. At the moment, you could add an identifier to standard data msg's from the front-end but there isn't a way to attach those to control msg's.