質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

3回答

3098閲覧

react classNameを変更したい

退会済みユーザー

退会済みユーザー

総合スコア0

Next.js

Next.jsは、Reactを用いたサーバサイドレンダリングなどを行う軽量なフレームワークです。Zeit社が開発しており、nextコマンドでプロジェクトを作成することにより、開発環境整備が整った環境が即時に作成できます。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

1クリップ

投稿2020/09/03 04:32

編集2020/09/03 04:39

react, typescript, next.js, styled-components を使って開発をしています。
useRefを使い,dom要素を取得してClickイベントが呼ばれた時にoption-containerclassNameにactiveを追加したいです。

useRefを使う前は下記のように書いていましたがClickのイベントが呼ばれた時にactiveに変更するにはどうしたらいいのでしょうか?
わかるかたいましたらご教授お願いしたいです。

selected.addEventListener("click", () => { optionContainer.classList.toggle("active"); });
import React, { FunctionComponent, useRef } from "react"; import styled from "styled-components"; const Container = styled.div` box-sizing: border-box; `; const SelectBox = styled.div` display: flex; width: 136px; flex-direction: column; font-size: 16px; color: #a3afbf; .option-container { font-size: 14px; box-shadow: 0px 1px 4px rgba(109, 123, 143, 0.12), 0px 4px 24px rgba(109, 123, 143, 0.25); color: rgba(0, 0, 0, 0.87); width: 100%; max-height: 0; opacity: 0; transition: all 0.2s; border-radius: 4px; overflow: hidden; order: 1; text-align: center; ::-webkit-scrollbar { width: 3px; background: #blue; border-radius: 0 4px 4px 0; } ::-webkit-scrollbar-thumb { background: #fff; border-radius: 0 4px 4px 0; } } .active { max-height: 150px; opacity: 1; overflow-y: scroll; } .option, .selected { padding: 12px 15px; cursor: pointer; } .option:hover { background: #dadee6; } .label { cursor: pointer; } .radio { display: none; } .selected { background: #f6f7f9; border-radius: 8px; margin-bottom: 8px; position: relative; order: 0; .name { display: inline-block; color: rgba(0, 0, 0, 0.87); font-size: 16px; } } .selected::after { content: ""; background: url("images/arrow_down.svg"); background-size: contain; background-repeat: no-repeat; margin-left: 30px; position: absolute; height: 100%; width: 15px; top: 18px; right: 10px; transition: all 0.4s; } .option-container.active + .selected::after { background: url("images/arrow_up.svg"); background-size: contain; background-repeat: no-repeat; } `; export const SelectDate: FunctionComponent = () => { const month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; const selected = useRef(null); const optionContainer = useRef(null); const optionList = useRef(null); // useRef使う前 // const selected = document.querySelector(".selected"); // const optionContainer = document.querySelector(".option-container"); // const optionsList = document.querySelectorAll(".option"); // selected.addEventListener("click", () => { // optionContainer.classList.toggle("active"); // }); // optionsList.forEach((o) => { // o.addEventListener("click", () => { // selected.innerHTML = o.querySelector("label").innerHTML; // optionContainer.classList.remove("active"); // }); // }); const Click = () => { console.log(selected.current); console.log(optionContainer.current); }; return ( <Container> <SelectBox> <div className="option-container" ref={optionContainer}> {month.map((month, i) => ( <div className="option" key={i} ref={optionList}> <input type="radio" className="radio" /> <label htmlFor="automobiles"> <p className="name">{month}月</p> </label> </div> ))} </div> <div className="selected" ref={selected} onClick={Click}> 年 </div> </SelectBox> </Container> ); };

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんにちは

私だったら、(とり急ぎ)このように修正すると思います、というコードを回答します。

修正のポイントは以下です。

  • SelectBox に prop active を追加して、これがtrue のとき、元のコードの .active に含まれていたスタイルが、.option-container のスタイルにマージされるようにした。

  • SelectDate で、2つの状態値、active と selectedMonth をuseStateする。useRef は不要。

  • div.option にクリックハンドラーを追加。これがクリックされたとき、selectedMonthが更新される。

  • <input type="radio"/>は不要となったのでいったん削除

以下が修正後のコードです。

tsx

1import React, { FunctionComponent, useState } from "react"; 2import styled from "styled-components"; 3 4const Container = styled.div` 5 box-sizing: border-box; 6`; 7 8type TSelectBox = { 9 active: boolean 10} 11const SelectBox = styled.div<TSelectBox>` 12 display: flex; 13 width: 136px; 14 flex-direction: column; 15 font-size: 16px; 16 color: #a3afbf; 17 .option-container { 18 font-size: 14px; 19 box-shadow: 0px 1px 4px rgba(109, 123, 143, 0.12), 20 0px 4px 24px rgba(109, 123, 143, 0.25); 21 color: rgba(0, 0, 0, 0.87); 22 width: 100%; 23 max-height: 0; 24 opacity: 0; 25 transition: all 0.2s; 26 border-radius: 4px; 27 overflow: hidden; 28 order: 1; 29 text-align: center; 30 ::-webkit-scrollbar { 31 width: 3px; 32 background: #blue; 33 border-radius: 0 4px 4px 0; 34 } 35 ::-webkit-scrollbar-thumb { 36 background: #fff; 37 border-radius: 0 4px 4px 0; 38 } 39 ${({ active }: TSelectBox) => active && ` 40 max-height: 150px; 41 opacity: 1; 42 overflow-y: scroll; 43 `} 44 } 45 .option, 46 .selected { 47 padding: 12px 15px; 48 cursor: pointer; 49 } 50 .option:hover { 51 background: #dadee6; 52 } 53 .label { 54 cursor: pointer; 55 } 56 .radio { 57 display: none; 58 } 59 .selected { 60 background: #f6f7f9; 61 border-radius: 8px; 62 margin-bottom: 8px; 63 position: relative; 64 order: 0; 65 .name { 66 display: inline-block; 67 color: rgba(0, 0, 0, 0.87); 68 font-size: 16px; 69 } 70 } 71 .selected::after { 72 content: ""; 73 background: url("images/arrow_down.svg"); 74 background-size: contain; 75 background-repeat: no-repeat; 76 margin-left: 30px; 77 position: absolute; 78 height: 100%; 79 width: 15px; 80 top: 18px; 81 right: 10px; 82 transition: all 0.4s; 83 } 84 .option-container.active + .selected::after { 85 background: url("images/arrow_up.svg"); 86 background-size: contain; 87 background-repeat: no-repeat; 88 } 89`; 90 91export const SelectDate: FunctionComponent = () => { 92 const months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 93 const [active, setActive] = useState<boolean>(false); 94 const [selectedMonth, setSelectedMonth] = useState<number>(0); 95 96 const handleActive = () => { 97 setActive(!active); 98 }; 99 100 const handleSelectingOption = (month: number) => { 101 setSelectedMonth(month); 102 setActive(false); 103 } 104 105 return ( 106 <Container> 107 <SelectBox active={active}> 108 <div className="option-container"> 109 {months.map((month, i) => ( 110 <div className="option" key={i} onClick={() => handleSelectingOption(month)}> 111 <label htmlFor="automobiles"> 112 <p className="name">{month}</p> 113 </label> 114 </div> 115 ))} 116 </div> 117 <div className="selected" onClick={handleActive}> 118 {selectedMonth > 0 ? `${selectedMonth}` : ``} 119 </div> 120 </SelectBox> 121 </Container> 122 ); 123}; 124

上記のコードを github.com/jun68ykt/q289304 に上げておきました。修正のコミットは、

です。補足すると、ラジオボタンを削除するなら、<label> も不要かもしれません。

以上、参考になれば幸いです。

備考

codesandbox にも上げてみました。一応、それっぽく動いているかなと思いますが、いかがでしょうか?

投稿2020/09/03 06:45

編集2020/09/03 07:32
jun68ykt

総合スコア9058

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/03 07:31

ありがとうございます!! 大変勉強になります。 最後の行の .option-container.active + .selected::after { background: url("images/arrow_up.svg"); background-size: contain; background-repeat: no-repeat; } `; が適応されず画像の矢印が切り替わらないのですがどう実装したらいいでしょうか?
退会済みユーザー

退会済みユーザー

2020/09/03 08:20

ありがとうございます!!!
jun68ykt

2020/09/03 08:22

解決したようですね、よかったです????
退会済みユーザー

退会済みユーザー

2020/09/03 08:34

ありがとうございました!!! 解決した後に聞いて申し訳ないですが 1月から12月のどれかが選択されたら選択された月の文字の色を黒色にしたく以下のようにif分でclassを分けてあげてcolorのスタイルをつけようと思ったのですがifのところで  式が必要です。というエラーになります。書いたコードは下記になります。もしよければ教えて欲しいです <div className="selected" onClick={handleActive}> { if (selectedMonth !== 0) { <p className="noSelect"> {selectedMonth > 0 ? `${selectedMonth}月` : `月`} </p> else { <p className="select"> {selectedMonth > 0 ? `${selectedMonth}月` : `月`} </p> }} </div>
jun68ykt

2020/09/03 10:08

上記の修正で、 <p>{selectedMonth || ''}月</p> としていますが、この || '' は、表示対象の数が 0 のときに 文字列として"0" 表示させないようにするために、よく使う手です。
退会済みユーザー

退会済みユーザー

2020/09/03 12:30

詳しくありがというございます!!! 思い通りに修正することができました
退会済みユーザー

退会済みユーザー

2020/09/04 02:50

昨日のselectboxを使っていて追加で質問があったのでこちらに投稿しました。 https://teratail.com/questions/289537?modal=q-comp もし良ければご教授してもらえると嬉しいです。
guest

0

useRefを使う前は下記のように書いていましたがClickのイベントが呼ばれた時にactiveに変更するにはどうしたらいいのでしょうか?

クラス自体をstateとして管理して、Clickイベントでそれを切り替えるようにしましょう。

useRefからDOMで書き換えるというのは、React管理しているHTML要素に対してやってはいけません

投稿2020/09/03 04:43

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

useStateactiveの状態を管理させてはどうでしょうか?

コメントの指摘を受けて修正しました。

javascript

1export const SelectDate: FunctionComponent = () => { 2 const month = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; 3 const [selectedMonth, setSelectedMonth] = useState("年"); 4 const [isSelectedActive, setIsSelectedActive] = useState(false); 5 const selected = useRef(null); 6 const optionContainer = useRef(null); 7 const optionList = useRef(null); 8 9 const handleClickSelected = () => { 10 console.log(selected.current); 11 console.log(optionContainer.current); 12 setIsSelectedActive(true); 13 }; 14 15 const handleClickOption = (month) => { 16 setSelectedMonth(month); 17 setIsSelectedActive(false); 18 }; 19 20 return ( 21 <Container> 22 <SelectBox> 23 <div className={"option-container" + isSelectedActive? : " active" : ""} ref={optionContainer}> 24 {month.map((month, i) => ( 25 <div className="option" key={i} ref={optionList} onClick={()=>{handleClickOption(month.toString())}}> 26 <input type="radio" className="radio" /> 27 <label htmlFor="automobiles"> 28 <p className="name">{month}</p> 29 </label> 30 </div> 31 ))} 32 </div> 33 <div className="selected" ref={selected} onClick={handleClickSelected}> 34 {selectedMonth} 35 </div> 36 </SelectBox> 37 </Container> 38 ); 39};

投稿2020/09/03 04:41

編集2020/09/03 05:33
nekoniki

総合スコア2411

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/03 04:53

ありがとうございます! 上記のように修正しましたがClickを押す前にclassNameがactiveだけになってしまいます。
退会済みユーザー

退会済みユーザー

2020/09/03 04:58

// optionsList.forEach((o) => { // o.addEventListener("click", () => { // selected.innerHTML = o.querySelector("label").innerHTML; // optionContainer.classList.remove("active"); // }); // }); clickした時に上記のも書き直したいのですがどのように書いたらいいでしょうか?
nekoniki

2020/09/03 05:34

すいません。回答を修正しました。 修正後のコードでは動作しますでしょうか?
退会済みユーザー

退会済みユーザー

2020/09/03 08:21

ありがとうございます!! 解決できました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問