Besides making it easy for crawlers to read the page content, NodeJS also helps with page refreshes. Imagine the following scenario. You made a React application with react routing. You hit the index page and everything is perfect. You can navigate between views and everything works perfectly fine. BUT THEN the user decides, for some reason, to refresh the page on the about page of your React application. A 404 page will be presented. But I made a route for the about page, why is it giving me a 404 page? Well for the simple reason that the entrance of you React application is under /. This means that unless you are on the home page and refresh, you will get a 404 page, because the root of your application can't be found. In AngularJS this can be solved by always pointing all page requests to the index.html page of your application and prepending the rest of the requested URL to the request in the Angular router. In React, in combination with Node, this is much, much simpler. What you can do through Node is to render the requested React view to a string, and simply serve this string as a response, just like how the SEO works. Because this time the crawler isn't the one requesting the page, but the user is, the browser will automatically render the HTML and the user will be presented with the right page. Once this HTML is rendered by the browser, React will automatically be kick started and ready for new requests and user actions.
Last but not least, loading speeds of pages can be drastically improved. Because NodeJS creates an HTML string on every page refresh, it can be very easily cached. This way Node can just look in the server memory and see if a cached version of the page exists. When it does, it can return this cached version instead of rendering the React view on the fly. Of course you should always set a maximum time between caches of pages, because otherwise it could be possible that your fancy updated pages will never actually be presented to the user and all your work will be for nothing. A good time guideline for pages that change often could be a few hours to a day. Other pages can be cached for a week or two. A good average is to cache pages for one day at a time, to make sure users get the updated experience soon enough, while still benefitting from the faster loading times of pages.
So what does it mean to share code between the server and the front-end? Well it means that user experiences are smooth, responds times are low, and implementing new features can be almost instantanious. There is no need to write the same logic twice (which I catch myself doing a lot in Angular), because the code for the front-end and backend is exactly the same. Because the code is exactly the same, SEO can be done easily, through server-side rendering, pages are always available, even after page refreshes, and page reloads can be made incredibly quick through page caching. Using the same language all across the application is quick, convenient, and it makes developing a delight, because you only need to know one language for everything.