実現したいこと
・追加残業時間を入力して"追加"ボタンを押下したら現状の残業時間に入力した残業時間をプラスして、現状発生している残業代を更新して表示したい
・"リセット"ボタンを押下したら現状の残業時間と現状発生している残業代をリセットしたい
前提
rails、react、typescriptで現状の残業時間と残業代を表示するアプリを作っています。
社員アカウントとしてログインしたら"forEmp.html.erb"を表示させて「残業代、残業時間、月の基本給、時給」を表示させるところまではできたのですが、追加残業時間を入力して"追加"を押下したり、"リセット"を押下したら「残業代、残業時間、月の基本給、時給」の表示が消えてしまいます。(リロードをすると残業代、残業時間が更新された状態で再度「残業代、残業時間、月の基本給、時給」が表示されます)
発生している問題・エラーメッセージ
追加残業時間を入力して"追加"を押下したり、"リセット"を押下したら残業代、残業時間、月の基本給、時給の表示が消えてしまう。(消えてしまう箇所はreactのコンポーネントをレンダリングさせて表示させている箇所なので、"追加"や"リセット"を押下してformを送信するとレンダリングされていないことが考えられる)
以下のエラーメッセージが関係している?
エラーメッセージ react-dom.development.js:74 Warning: You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root.render() on the existing root instead if you want to update it. printWarning @ react-dom.development.js:74 error @ react-dom.development.js:51 warnIfReactDOMContainerInDEV @ react-dom.development.js:25429 createRoot @ react-dom.development.js:25326 createRoot$1 @ react-dom.development.js:25704 ./node_modules/react-dom/client.js.exports.createRoot @ client.js:12 createReactRootLike @ renderHelpers.js:13 mountComponents @ index.js:114 ./node_modules/react_ujs/react_ujs/index.js.ReactRailsUJS.handleMount @ index.js:144 domContentLoadedCheck @ es-module-shims.js:797 (anonymous) @ es-module-shims.js:803
#該当のソースコード
forEmp.html.erb
<%= react_component("ShowData", {data: @overtimePay, label: "今月の残業代"}) %> <%= react_component("ShowData", {data: @overtime, label: "今月の残業時間"}) %> <%= react_component("ShowData", {data: @monthlyPay, label: "現在の月給"}) %> <%= react_component("ShowData", {data: @hourlyWage, label: "現在の時給"}) %> <%= form_with url: emp_info_path, method: :post do |form| %> <%= form.label :"追加残業時間" %> <%= form.text_field :additionalOvertime %> <%= form.submit value = "追加"%> <% end %> <%= form_with url: reset_path, method: :post do |f| %> <%= f.submit "リセット" %> <% end %>
ShowData.tsx
import React, { useState, ChangeEvent } from "react"; import PropTypes from "prop-types"; interface ShowDataProps { data: number; label: string } const ShowData: React.FC<ShowDataProps> = ({ data, label }) => { return ( <> <div>{label}</div> <div>{data}</div> </> ); }; ShowData.propTypes = { data: PropTypes.number.isRequired, label: PropTypes.string.isRequired, } as const; export default ShowData;
overtime_controller.rb
class OvertimeController < ApplicationController def forEmp empInfo = EmpInfo.find_by(users_id: current_user.id) @monthlyPay = empInfo.salary @hourlyWage = @monthlyPay / 160 @overtime = empInfo.overtime if @overtime < 30 overtimeForCulcurate = 0 else overtimeForCulcurate = @overtime - 30 end @overtimePay = @hourlyWage * overtimeForCulcurate end def reset empInfo = EmpInfo.find_by(users_id: current_user.id) empInfo.update(overtime: 0) redirect_to action: :forEmp end def administration @emp_names = User.pluck(:name) end def setting @emp_info = User.find(params[:id]) end def new empInfo = EmpInfo.find_by(users_id: current_user.id) @overtime = empInfo.overtime + params[:additionalOvertime] @overtimePay = @overtime*2000 end def update empInfo = EmpInfo.find_by(users_id: current_user.id) additionalOvertime = params[:additionalOvertime] intAdditionalOvertime = additionalOvertime.to_i if intAdditionalOvertime == nil or intAdditionalOvertime < 0 else overtime = empInfo.overtime + intAdditionalOvertime empInfo.update(overtime: overtime) end empInfo.save redirect_to forEmp_path end end
routes.rb
Rails.application.routes.draw do root to: 'home#top' get 'overtime/forEmp' , to: 'overtime#forEmp', as: :forEmp post 'overtime/update' , to: 'overtime#update', as: :emp_info post 'overtime/new' , to: 'overtime#new', as: :emp_infos post 'overtime/reset' , to: 'overtime#reset', as: :reset get 'overtime/administration' , to: 'overtime#administration', as: :administration post 'overtime/setting', to: 'overtime#setting', as: :setting get 'administrator/viewEmpInfo' , to: 'administrator#viewEmpInfo', as: :selectedEmp devise_for :users # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/") # root "articles#index" devise_scope :user do get '/users/sign_out' => 'devise/sessions#destroy' end end
application.html.erb
<!DOCTYPE html> <html> <head> <title>PaidHoliday</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> <%= javascript_pack_tag 'application' %> <% if request.path != '/users/sign_in'%> <% if user_signed_in? %> <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %> <% else %> <%= link_to 'ログイン', new_user_session_path %> <% end %> <% end %> </head> <body> <%= yield %> </body> </html>
application.js
中身なし(中身なしでも動くことが分かったため)
server_rendering.js
// By default, this pack is loaded for server-side rendering. // It must expose react_ujs as `ReactRailsUJS` and prepare a require context. var componentRequireContext = require.context("components", true); var ReactRailsUJS = require("react_ujs"); ReactRailsUJS.useContext(componentRequireContext);
webpack.config.js
const path = require('path'); module.exports = { entry: './app/javascript/packs/application.js', output: { path: path.resolve(__dirname, 'public'), filename: 'bundle.js', }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }, module: { rules: [ { test: /\.(ts|tsx)$/, exclude: /node_modules/, use: 'ts-loader', }, ], }, mode: 'development', // 開発モード };
試したこと
・createRoot()を使用している箇所はありません
・試しにapplication.html.erbの「<%= javascript_pack_tag 'application' %>」を消すとリロードをしても「残業代、残業時間、月の基本給、時給」が表示されなくなりました
・react_railsを使用しているため、reactdomは使用していません
補足情報(FW/ツールのバージョンなど)
エディタ:VScode
DB:SQLite

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。