20210731のReactに関する記事は3件です。

[React]Material UIのテーブルを使ったときに、コードが汚くなったので調整した。

Material UIは動くサンプルをカタログ的に選んですぐ使えますが、 一方で、理解できていないまま使ってしまうということにもなりがちです。 私は特にテーブルコンポーネントを扱うときに、ちょっと雑に扱っていた気がします。 コンポーネントによってはサンプルが結構行数が長くなってしまうのが原因だと思ってます。 Material-UI | Table Custom pagination optionsをベースに使っていたのですが、175行と少しコード量があります。 また、Sorting $ selecting は382行あります。 微調整をして、多少汚かったり理解していないコードがあっても、 コンポーネントに閉じてしまえばどうにかなるのですが、 それでは変更も加えづらいので、よくないです。 カタログ的に並んでいてソースもコピーできるのですが、 - 最小限の構成を理解する - その後必要な要素を付け足す - スタイルをStyled component風に書く の方針で進めていったほうが良さそうです。 それでは見ていきましょう。 Basic tableを理解して、コンポーネントとして使えるようにする。 こういうのは一番シンプルなものから見ていくのが理解がしやすいですよね。 とりあえず公式のBasic tableから見ていきます。 こんな感じです。 import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; import TableCell from '@material-ui/core/TableCell'; import TableContainer from '@material-ui/core/TableContainer'; import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; import Paper from '@material-ui/core/Paper'; const useStyles = makeStyles({ table: { minWidth: 650, }, }); function createData(name: string, calories: number, fat: number, carbs: number, protein: number) { return { name, calories, fat, carbs, protein }; } const rows = [ createData('Frozen yoghurt', 159, 6.0, 24, 4.0), createData('Ice cream sandwich', 237, 9.0, 37, 4.3), createData('Eclair', 262, 16.0, 24, 6.0), createData('Cupcake', 305, 3.7, 67, 4.3), createData('Gingerbread', 356, 16.0, 49, 3.9), ]; export default function BasicTable() { const classes = useStyles(); return ( <TableContainer component={Paper}> <Table className={classes.table} aria-label="simple table"> <TableHead> <TableRow> <TableCell>Dessert (100g serving)</TableCell> <TableCell align="right">Calories</TableCell> <TableCell align="right">Fat&nbsp;(g)</TableCell> <TableCell align="right">Carbs&nbsp;(g)</TableCell> <TableCell align="right">Protein&nbsp;(g)</TableCell> </TableRow> </TableHead> <TableBody> {rows.map((row) => ( <TableRow key={row.name}> <TableCell component="th" scope="row"> {row.name} </TableCell> <TableCell align="right">{row.calories}</TableCell> <TableCell align="right">{row.fat}</TableCell> <TableCell align="right">{row.carbs}</TableCell> <TableCell align="right">{row.protein}</TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); } createData関数でデータを使っていますが、 上記のようになっていますが、親コンポーネントで使うとしたらこんな感じにしたくないでしょうか。 <BasicTable headers={["headerA", "headerB", "headerC", "headerD",]} datas={ [ {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"}, {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"}, {A: "dataA", B: "dataB", C: "dataC", D: "dataD", E: "dataE"}, ] } /> その場合、createDataやrowsなどは必要なくなります。 また、TableCellの記述もmapを使った形式に変わっていきます。 import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import Table from '@material-ui/core/Table'; import TableBody from '@material-ui/core/TableBody'; import TableCell from '@material-ui/core/TableCell'; import TableContainer from '@material-ui/core/TableContainer'; import TableHead from '@material-ui/core/TableHead'; import TableRow from '@material-ui/core/TableRow'; import Paper from '@material-ui/core/Paper'; const useStyles = makeStyles({ table: { minWidth: 650, }, }); export default function BasicTable({headers, datas}) { const classes = useStyles(); return ( <TableContainer component={Paper}> <Table className={classes.table} aria-label="simple table"> <TableHead> <TableRow> {headers.map((header) => { <TableCell align="right" key{header}>header</TableCell> })} </TableRow> </TableHead> <TableBody> {datas.map((data, i) => ( <TableRow key={'tableData' + i}> <TableCell align="right">{data.A}</TableCell> <TableCell align="right">{data.B}</TableCell> <TableCell align="right">{data.C}</TableCell> <TableCell align="right">{data.D}</TableCell> <TableCell align="right">{data.E}</TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); } こうすると、かなりスッキリして見通しよくなってきましたね。 makeStylesとuseStylesでTableをスタイリングしていることがわかります。 Table、TableHead、TableBody、TableRow、TableCellも大体わかると思います。 だけちょっと気になりますよね。 componentは、HTMLタグ名(例: 'div')やコンポーネント名(例: Paper)を指定できます。 この場合、Paperコンポーネントをスタイリングを利用しています。 これで、Simple Componentが理解できました。 これに、付け加えていく形で進めていくと良さそうです。 カスタムスタイルをStyled components風に分離する。 上記のコード例だと、スタイルを調整するmakeStylesの行数も5行と少ないです。ただ、実装したい内容によってはどんどん結構長くなってしまいます。 また、useStylesとかmakeStylesとかcreateStylesとか使いたくないなと思っていました。 classes.classNameのような形で設定しなければいけないのもちょっと嫌だなと思っていました。 どうにか回避する方法はないかなと思ったらありました。 Material-UI | styles Styled components API import React from 'react'; import { styled } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; const MyButton = styled(Button)({ background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)', border: 0, borderRadius: 3, boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)', color: 'white', height: 48, padding: '0 30px', }); export default function StyledComponents() { return <MyButton>Styled Components</MyButton>; } 上記のようにStyled component風に書くことができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactを使用したRailsアプリをRspecで統合テストする方法

はじめに この記事では, React(react-rails)を使用したRailsアプリの統合テストをする方法について書いています. RSpecで統合テストを書こうとした際に色々ハマったポイントがあるので, そこを重点的に解説します. 【動作環境】 Rails 6.1.4 RSpec 3.10 1. ひとまず書いてみる まず他の記事などを参考にCapybaraというgemをインストールします. これによりユーザーがブラウザで行うような操作をCapybaraのメソッドで実行することができます. 統合テストで重宝するgemのようです. spec/features/signup.rb gem 'capybara', '>= 2.15' 早速, featureというフォルダの中に統合テストファイルを作成し, topページに行ってアカウント登録ボタンを押す操作を書きます 以下のvisitやclick_buttonなどがCapybaraのメソッドになります. spec/features/signup.rb require 'rails_helper' feature "Signup" do example "新規登録後にユーザーページが表示される" do visit "/" click_button "新規アカウント登録" end end 統合テストデビューに歓喜し意気揚々とでbundle exec rspecを実行すると以下のエラーが. Failures: 1) Signup 新規登録後にユーザーページが表示される Failure/Error: click_button("新規アカウント登録") Capybara::ElementNotFound: Unable to find button "新規アカウント登録" that is not disabled # ./spec/features/user_spec.rb:6:in `block (2 levels) in <top (required)>' 指定された"新規アカウント登録"なんてbuttonタグないけど?と怒られています. いやあるでしょ? こっちはchromeの検証機能使ってあるのを確認してるんですが? いろいろ調べたところ, 純粋なRailsアプリであればこれで動くようですが, 今回はReactを導入したことが原因で動きません. 2. :js => true が必要 解決するには, 以下のように「:js => true」を追記してやります. これを書かないとjsファイルが読み込まれず, Reactのコンポーネントが描画されないようです. spec/features/signup.rb require 'rails_helper' + feature "Signup", :js => true do - feature "Signup" do example "新規登録後にユーザーページが表示される" do visit "/" click_button "新規アカウント登録" end end これでreactのcomponentも描画されるようになりました. 3. selenium-webdriver が必要 もう一度, ターミナルでbundle exec rspecを実行してみると今度は以下のエラーが出ます. Failures: 1) Signup 新規登録後にユーザーページが表示される Failure/Error: visit "/" LoadError: Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler. 「Capybaraのselenium driverはselenium-webdriverを読み込めないので, gem 'selenium-webdriver'をインストールしてください」と教えてくれています. その通りにgemを追加しbundle installします. Gemfile group :test do gem 'capybara', '>= 2.15' + gem 'selenium-webdriver' gem 'rspec-rails' gem "factory_bot_rails" gem 'faker' end 4. Firefoxをダウンロード 3度目の正直で, ターミナルでbundle exec rspecを実行してください. 無事以下のエラーが出ます. Failures: 1) Signup 新規登録後にユーザーページが表示される Failure/Error: visit "/" Selenium::WebDriver::Error::WebDriverError: Could not find Firefox binary (os=macosx). Make sure Firefox is installed or set the path manually with Selenium::WebDriver::Firefox::Binary.path= 言われた通りにFirefoxをダウンロードします. $ brew install --appdir="/Applications" firefox もう一度, ターミナルでbundle exec rspecを叩きますが, 以下のエラー. Failures: 1) Signup 新規登録後にユーザーページが表示される Failure/Error: visit "/" Selenium::WebDriver::Error::WebDriverError: Unable to find Mozilla geckodriver. Please download the server from https://github.com/mozilla/geckodriver/releases and place it somewhere on your PATH. More info at https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/WebDriver. 以下で解決します. $ brew install geckodriver 以上で テストが通るようになりました. これで, bundle exec rspecを叩くとfirefoxが起動して実際にブラウザの操作をしてくれます.お疲れ様でした. 5. 新規登録Formに値を入力し, 登録ボタンを押すまで あとは以下のようにCapybaraを使って統合テストを書いていくだけです. ここでは新規登録Formに値を入力し登録ボタンを押しています. なお, 今回はReactによってSPA化しているため正しいページにリダイレクトされているか確認するコードは含まれていません. spec/features/signup.rb require 'rails_helper' feature "Signup" , :js => true do example "新規登録後にユーザーページが表示される" do visit "/" click_button("新規アカウント登録") fill_in 'user_name', with:'test_user' fill_in 'email', with:'hogehoge@hoge.com' fill_in 'password', with:'password' fill_in 'password_confirm', with:'password' click_button("登録") end end 最後に 私は原因がわからず解決に2時間ほどハマってしまいました. この記事によって少しでも救われる人がいれば幸いです.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

emotionの型エラーが出たとき・スタイルが反映されないときの対処法

バージョン @emotion/react: 11.4.0 型エラーが出たとき tsconfig.jsonに以下を追記。 { "compilerOptions": { //・・・ "types": ["@emotion/react/types/css-prop"], } } コンパイルされないとき emotionのコンパイルはemotion独自のコンパイラを通す必要があるみたいです。 ソースコードの頭で以下の宣言をするとスタイルが効きます /** @jsxImportSource @emotion/react */ import React from "react"; import { css } from "@emotion/react"; const App = () => { return ( <div> <p css={css`color: green;`} >hello</p> </div> ) } この頭に書いたものを「JSX Pragma」というそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む