Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
175 views
in Technique[技术] by (71.8m points)

ruby on rails - Standalone React components with Rails6 / Webpacker

I'd like to know how to / [accepted way] to add standalone react components to specific pages in rails, using webpacker. The use case is that I have a Rails6 app that I intend to use Rails functionalities for the view, instead of a full React SPA. I would, however, like to use specific custom react components in specific rails views. The app has webpacker installed and configured for react.

Questions I have:

  1. is react-rails the right gem / pattern for this usage? I have tried using it and it does perfectly fill the use case, but I was wondering if it can be done without adding this gem since it since it seems like webpacker itself has react support.
  2. Is it required that the webpacker <%= javascript_pack_tag => should always go in an application layout (head tag), and dynamically render a pack to the end of the body(appendChild), like the examples say? I'd rather include the pack tag in a view, and have it render directly to a div I've specified. (code for this below)
  3. How does one send react props to a standalone react component that is rendered by the <%= javascript_pack_tag => ? Would the component have to be written to fetch any data it needs on mount?

Things I've tried:

  1. I looked through the documentation for webpacker, and as many of the issues I could find using the keywords "standalone" and "react" and couldn't find anything.
  2. Sample project below: it works.. but I'm not sure if it's the right way to do this and I'm not sure how to address question 3 from above (regarding passing props)

Initialize

rails new petstore --webpack=react
bin/rails generate scaffold Pet pet_type:string pet_name:string
bin/rails db:migrate

package.json

{
  "name": "petstore",
  "private": true,
  "dependencies": {
    "@babel/preset-react": "^7.12.10",
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "5.2.1",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "prop-types": "^15.7.2",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "turbolinks": "^5.2.0"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack-dev-server": "^3.11.2"
  }
}

config/webpacker.yml

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_root_path: public
  public_output_path: packs
  cache_path: tmp/cache/webpacker
  webpack_compile_output: true

  # Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']
  additional_paths: []

  # Reload manifest.json on all requests so we reload latest compiled packs
  cache_manifest: false

  # Extract and emit a css file
  extract_css: false

  static_assets_extensions:
    - .jpg
    - .jpeg
    - .png
    - .gif
    - .tiff
    - .ico
    - .svg
    - .eot
    - .otf
    - .ttf
    - .woff
    - .woff2

  extensions:
    - .jsx
    - .mjs
    - .js
    - .sass
    - .scss
    - .css
    - .module.sass
    - .module.scss
    - .module.css
    - .png
    - .svg
    - .gif
    - .jpeg
    - .jpg

development:
  <<: *default
  compile: true

  # Reference: https://webpack.js.org/configuration/dev-server/
  dev_server:
    https: false
    host: localhost
    port: 3035
    public: localhost:3035
    hmr: false
    # Inline should be set to true if using HMR
    inline: true
    overlay: true
    compress: true
    disable_host_check: true
    use_local_ip: false
    quiet: false
    pretty: false
    headers:
      'Access-Control-Allow-Origin': '*'
    watch_options:
      ignored: '**/node_modules/**'


test:
  <<: *default
  compile: true

  # Compile test packs to a separate directory
  public_output_path: packs-test

production:
  <<: *default

  # Production depends on precompilation of packs prior to booting for performance.
  compile: false

  # Extract and emit a css file
  extract_css: true

  # Cache manifest.json for performance
  cache_manifest: true

app/javascript/components/PetAnimation.js

import React from "react";
import PropTypes from "prop-types"

class PetAnimation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      petType: props.petType,
    };
  }

  render() {
    return (
      <div>Cute Pet Animation based on Pet Type and other imported libraries</div>
    )
  }
}

PetAnimation.propTypes = {
  petType: PropTypes.string
};

export default PetAnimation;

app/javascript/packs/pet_animation.js

import React from 'react'
import ReactDOM from 'react-dom'
import PetAnimation from "../components/PetAnimation";

document.addEventListener('DOMContentLoaded', () => {
  const rootElement = document.getElementById("pet-animation");
  if (rootElement != null) {
    ReactDOM.render(<PetAnimation/>, rootElement)
  }
})

app/views/pets/show.html.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Pet type:</strong>
  <%= @pet.pet_type %>
</p>

<p>
  <strong>Pet name:</strong>
  <%= @pet.pet_name %>
</p>

<p>
  <%= javascript_pack_tag 'pet_animation', 'data-turbolinks-track': 'reload' %>
  <div id="pet-animation"></div>
</p>
<%= link_to 'Edit', edit_pet_path(@pet) %> |
<%= link_to 'Back', pets_path %>

... and it works, sort of: petstore_show

question from:https://stackoverflow.com/questions/65949235/standalone-react-components-with-rails6-webpacker

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...