2

I'm using react-rails (with sprockets rather than webpack, if it turns out to be relevant), trying to make a reusable component for a sprawling rails application. It's basically a navbar, and we have a list of links we usually want to display, but we also need to be able to override that list on some pages.

So far so good. However!

We have the array of links saved as a constant in our rails app, and ideally, the default links would be the defaultProps for the react component. We don't want to duplicate that information in the react component, because the whole point of making this component is that we're trying to move toward consistency, and if we need to make updates hopefully we'll only make them in one place.

So this is an option:

<%= react_component "Navbar", links: navbar_default_links, other_settings: true, etc: false %>

But having to do that on every page seems inelegant when really we just want to call out when the links are different than the usual ones.

Does anyone know a way to pull information from Rails into the definition of the react component using react-rails? Or another solution?

(Edit: to be clear, this doesn't need to be information from the rails database)

Clara B
  • 461
  • 4
  • 14

1 Answers1

1

Here are the ways I'm aware of to communicate to share constants between Rails and React.

Option #1: Wrap react_component

def render_navbar(props = {}, options = {})
  react_component 'Navbar', {links: navbar_default_links}.merge(props), options
end

Option #2: (If you use Webpack) Declare the links in a JSON or YAML that both Rails and your bundler can consume.

# The file that used to define the constant
def navbar_default_links
  JSON.load(File.read(Rails.root.join('path/to/your/file.json')))
end
// In `Navbar.js`, using json-loader
import navbarDefaultLinks from './path/to/navbar_default_links.json';

Option #3 (If you use the Asset pipeline) Add .erb to your JS file and use the constant

// Navbar.js.erb
const defaultProps = <%= MyModule::NAVBAR_DEFAULT_LINKS %>

Options #4 Communicate through a global object like window. It breaks encapsulation but hey ‍♂️ In application.html.erb

<script>
  window.navbar_default_links = <%= MyModule::NAVBAR_DEFAULT_LINKS %>
</script>
<%= `window.navbar_default_links` must be above this line %>
<%= javascript_pack_tag 'application' %>
// In `navbar.js`
const navbarDefaultLinks = window.navbar_default_links
Matthieu Libeer
  • 2,286
  • 1
  • 12
  • 16