Skip to content

Commit 89cdc9f

Browse files
committed
Add test case for re-mounting components without reloading the page
1 parent e4814bd commit 89cdc9f

File tree

14 files changed

+277
-132
lines changed

14 files changed

+277
-132
lines changed

Appraisals

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ end
1717
appraise 'shakapacker' do
1818
gem 'rails', '~> 7.0.x'
1919
gem 'shakapacker', '7.0.2'
20+
gem 'turbo-rails'
2021
end
2122

2223
appraise 'base' do

gemfiles/base.gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ GEM
236236
thor (1.2.2)
237237
tilt (2.2.0)
238238
timeout (0.4.0)
239+
turbo-rails (1.4.0)
240+
actionpack (>= 6.0.0)
241+
activejob (>= 6.0.0)
242+
railties (>= 6.0.0)
239243
tzinfo (2.0.6)
240244
concurrent-ruby (~> 1.0)
241245
websocket (1.2.9)
@@ -267,6 +271,7 @@ DEPENDENCIES
267271
react-rails!
268272
selenium-webdriver
269273
test-unit (~> 2.5)
274+
turbo-rails
270275

271276
BUNDLED WITH
272277
2.4.9

gemfiles/shakapacker.gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ source "http://rubygems.org"
44

55
gem "rails", "~> 7.0.x"
66
gem "shakapacker", "7.0.2"
7+
gem "turbo-rails"
78

89
gemspec path: "../"

gemfiles/shakapacker.gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ GEM
244244
thor (1.2.2)
245245
tilt (2.2.0)
246246
timeout (0.4.0)
247+
turbo-rails (1.5.0)
248+
actionpack (>= 6.0.0)
249+
activejob (>= 6.0.0)
250+
railties (>= 6.0.0)
247251
tzinfo (2.0.6)
248252
concurrent-ruby (~> 1.0)
249253
websocket (1.2.9)
@@ -276,6 +280,7 @@ DEPENDENCIES
276280
selenium-webdriver
277281
shakapacker (= 7.0.2)
278282
test-unit (~> 2.5)
283+
turbo-rails
279284

280285
BUNDLED WITH
281286
2.4.9
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class CountersController < ApplicationController
2+
def index
3+
@counters = [{ name: "Counter 1" }]
4+
end
5+
6+
def create
7+
@counter = { name: "Counter 2" }
8+
end
9+
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var React = require("react");
2+
var createReactClass = require("create-react-class");
3+
4+
module.exports = createReactClass({
5+
getInitialState: function () {
6+
return { count: 0 };
7+
},
8+
handleClick: function () {
9+
this.setState({ count: this.state.count + 1 });
10+
},
11+
render: function () {
12+
return (
13+
<div>
14+
<p>
15+
{this.props.name} - {this.state.count}
16+
</p>
17+
<button type="button" onClick={this.handleClick}>
18+
Increment {this.props.name}
19+
</button>
20+
</div>
21+
);
22+
},
23+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var { Controller } = require("@hotwired/stimulus");
2+
var ReactRailsUJS = require("react_ujs");
3+
4+
module.exports = class extends Controller {
5+
connect() {
6+
this.observeChange();
7+
}
8+
9+
disconnect() {
10+
this.observer.disconnect();
11+
}
12+
13+
observeChange() {
14+
var element = this.element;
15+
var callback = function (mutationsList, _observer) {
16+
mutationsList.forEach(function (mutation) {
17+
if (mutation.type === "childList") {
18+
ReactRailsUJS.mountComponents(element);
19+
}
20+
});
21+
};
22+
23+
this.observer = new MutationObserver(callback);
24+
this.observer.observe(this.element, { childList: true });
25+
}
26+
};
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
var ctx = require.context("components", true)
2-
var ReactRailsUJS = require("react_ujs")
3-
ReactRailsUJS.useContext(ctx)
4-
var React = require("react")
1+
require("@hotwired/turbo-rails");
2+
var { Application } = require("@hotwired/stimulus");
3+
var MountCountersController = require("../controllers/mount_counters");
54

6-
window.GlobalComponent = function(props) {
7-
return React.createElement("h1", null, "Global Component")
8-
}
5+
window.Stimulus = Application.start();
6+
Stimulus.register("mount-counters", MountCountersController);
7+
8+
var ctx = require.context("components", true);
9+
var ReactRailsUJS = require("react_ujs");
10+
ReactRailsUJS.useContext(ctx);
11+
var React = require("react");
12+
13+
window.GlobalComponent = function (props) {
14+
return React.createElement("h1", null, "Global Component");
15+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<%= turbo_stream.append :counters do %>
2+
<%= react_component("Counter", @counter) %>
3+
<% end %>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<h2>React 18 bug reproduction</h2>
2+
3+
<%= turbo_frame_tag :counters, data: { controller: "mount-counters" } do %>
4+
<% @counters.each do |counter| %>
5+
<%= react_component("Counter", counter) %>
6+
<% end %>
7+
<% end %>
8+
<%= form_with(url: counters_path, method: :post, data: { turbo: true, turbo_stream: true }) do |form| %>
9+
<%= form.submit "Add counter" %>
10+
<% end %>

test/dummy/config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Dummy::Application.routes.draw do
44
get "no-turbolinks", to: "pages#no_turbolinks"
55
resources :pages, only: [:show]
6+
resources :counters, only: [:create, :index]
67
resources :server, only: [:show] do
78
collection do
89
get :console_example

test/dummy/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
"@babel/preset-react": "^7.17.12",
77
"@babel/preset-typescript": "^7.17.12",
88
"@babel/runtime": "^7.18.3",
9+
"@hotwired/stimulus": "^3.2.2",
10+
"@hotwired/turbo-rails": "^7.3.0",
911
"babel-loader": "^8.2.5",
1012
"babel-plugin-macros": "^3.1.0",
1113
"compression-webpack-plugin": "^9.2.0",
@@ -14,8 +16,8 @@
1416
"css-minimizer-webpack-plugin": "^2.0.0",
1517
"mini-css-extract-plugin": "^1.6.2",
1618
"pnp-webpack-plugin": "^1.7.0",
17-
"react": "^17.0.2",
18-
"react-dom": "^17.0.2",
19+
"react": "^18.2.0",
20+
"react-dom": "^18.2.0",
1921
"react_ujs": "file:.yalc/react_ujs",
2022
"shakapacker": "7.0.2",
2123
"style-loader": "^3.3.1",

0 commit comments

Comments
 (0)