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

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

React.js

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

Q&A

解決済

1回答

1872閲覧

コンポーネントを描画するたびに、要素の位置をランダムに配置したい。

whoiwhoi

総合スコア48

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

CSS

CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

React.js

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

0グッド

0クリップ

投稿2020/01/08 03:25

編集2020/01/09 04:30

動的に描画するコンポーネントにある要素を、描画するたびに違う位置に配置したいです。
下記はサンプルです。

サンプル

ランダムボタンを押すとランダムコンポーネントが描画されます。
ランダムコンポーネントにある赤ボタンにonMouseDownするとクリック中と表示し、onMouseUpするとクリック中の表示が消えます。
ランダムコンポーネントにあるトップボタンを押すと、ランダムコンポーネントをアンマウントします。

発生している問題

コンポーネントの描画毎に赤ボタンをランダムに配置できていますが、マウスイベントを実行するたびに、赤ボタンの位置が変更してしまいます。
マウスイベントでクリック中のstateを更新しているため、stateの更新による再レンダーで赤ボタンが移動しているかと思います。
stateの管理はHooksを利用しています。

実現したいこと

マウスイベントによって赤ボタンが移動することがないようにしたいです。
それを踏まえた上で、コンポーネントの描画毎に赤ボタンをランダムに配置したいです。

ソースコード

・Random.jsx

jsx

1/** @jsx jsx */ 2import React, { useState } from "react"; 3import { jsx, css } from "@emotion/core"; 4 5const Random = ({ setRandom }) => { 6 const click = () => { 7 setRandom(false); 8 }; 9 10 const [clicking, setClicking] = useState(false); 11 const down = () => setClicking(true); 12 const up = () => setClicking(false); 13 14 const randomAreaWidth = window.screen.width; 15 const randomAreaHight = window.screen.height - 100; 16 let maxTop = randomAreaWidth * 0.3; 17 let maxLeft = randomAreaHight * 0.2; 18 const top = Math.random() * (maxTop + 1); 19 const left = Math.random() * (maxLeft + 1); 20 const button = css` 21 background: red; 22 border: none; 23 color: white; 24 cursor: pointer; 25 width: 60px; 26 height: 60px; 27 transform: translate(${top}px, ${left}px); 28 `; 29 30 return ( 31 <React.Fragment> 32 <header css={header}> 33 <h2>ランダム</h2> 34 <button onClick={click}>トップ</button> 35 {clicking === true && <p>クリック中</p>} 36 </header> 37 <hr /> 38 <button css={button} onMouseDown={down} onMouseUp={up}> 39 ボタン 40 </button> 41 </React.Fragment> 42 ); 43}; 44 45const header = css` 46 display: flex; 47 align-items: center; 48 height: 50px; 49 h2, 50 button { 51 margin-right: 16px; 52 } 53`; 54 55export default Random; 56

・App.jsx

jsx

1/** @jsx jsx */ 2import React, { useState } from "react"; 3import { jsx } from "@emotion/core"; 4import Random from "./Random"; 5 6export default function App() { 7 const [random, setRandom] = useState(false); 8 const click = () => { 9 setRandom(true); 10 }; 11 12 return ( 13 <React.Fragment> 14 <h1>トップ</h1> 15 <button onClick={click}>ランダム</button> 16 {random === true && <Random setRandom={setRandom} />} 17 </React.Fragment> 18 ); 19}

使用しているCSSフレームワーク

EmotionをCSS in JS記法で使用しています。

試したこと

1. 赤ボタンのCSSをランダムコンポーネントの外に移す
サンプル
マウスイベントのたびに赤ボタンが移動することは無くなりましたが、コンポーネントの描画毎にランダム配置ができず、毎回同じ位置に描画されます。
初回描画時のみランダムに配置できています。

2. クリック中かどうかをstateで管理しない
サンプル
再レンダーを防ぐためにクリック中かどうかをstateで管理せず、マウスダウンとアップのイベントそれぞれでtrueとfalseを変数に代入することで、マウスイベント毎の赤ボタンの移動は無くなりました。
しかし、クリック中メッセージの表示の切り替えができません。

3. 試したこと2 + クリック中メッセージの表示をCSSで切り替える
サンプル
クリック中メッセージの表示の切り替えを、

jsx

1{clicking && <p>クリック中</p>}

上記のような論理 && 演算子によるインライン Ifではなく、下記のようにCSSで切り替える方向で試してみました。

jsx

1const clickingMessage = css` 2 display: ${clicking ? "block" : "none"}; 3`;

しかし2.と同じでクリック中かどうかをstateで管理していないため、displayの三項演算子は描画時しか実行されませんでした、

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは、whoiwhoiさん

質問拝見しました。

ご認識の通り、Random.jsx内のCSSでtopleftのポジションを指定しているので、onMouseDownの時点で、Randomコンポーネントの再レンダリングが走り、その時点でtopleftが更新され、赤ボタンが移動することになります。

「ランダム」ボタンを押したときのみ、topleftの値を更新したいということは、親コンポーネントApp.jsxでポジションの値を保持して、「ランダム」ボタンを押したときにポジションの値を更新すると良さそうです。

コード例としては、以下になります

App.jsx

jsx

1/** @jsx jsx */ 2import React, { useState } from "react"; 3import { jsx } from "@emotion/core"; 4import Random from "./Random"; 5 6export default function App() { 7 const createPosition = () => { 8 const randomAreaWidth = window.screen.width; 9 const randomAreaHight = window.screen.height - 100; 10 let maxTop = randomAreaWidth * 0.3; 11 let maxLeft = randomAreaHight * 0.2; 12 const top = Math.random() * (maxTop + 1); 13 const left = Math.random() * (maxLeft + 1); 14 15 return [top, left]; 16 }; 17 const [top, left] = createPosition(); 18 19 const [random, setRandom] = useState(false); 20 const [position, setPosition] = useState({ top, left }); 21 22 const click = () => { 23 const [top, left] = createPosition(); 24 setPosition({ top, left }); 25 setRandom(true); 26 }; 27 28 return ( 29 <React.Fragment> 30 <h1>トップ</h1> 31 <button onClick={click}>ランダム</button> 32 {random === true && <Random setRandom={setRandom} position={position} />} 33 </React.Fragment> 34 ); 35} 36 37

Random.jsx

jsx

1/** @jsx jsx */ 2import React, { useState } from "react"; 3import { jsx, css } from "@emotion/core"; 4 5const Random = ({ setRandom, position }) => { 6 const click = () => { 7 setRandom(false); 8 }; 9 10 const [clicking, setClicking] = useState(false); 11 const down = () => setClicking(true); 12 const up = () => setClicking(false); 13 14 const { top, left } = position; 15 const button = css` 16 background: red; 17 border: none; 18 color: white; 19 cursor: pointer; 20 width: 60px; 21 height: 60px; 22 transform: translate(${top}px, ${left}px); 23 `; 24 25 return ( 26 <React.Fragment> 27 <header css={header}> 28 <h2>ランダム</h2> 29 <button onClick={click}>トップ</button> 30 {clicking === true && <p>クリック中</p>} 31 </header> 32 <hr /> 33 <button css={button} onMouseDown={down} onMouseUp={up}> 34 ボタン 35 </button> 36 </React.Fragment> 37 ); 38}; 39 40const header = css` 41 display: flex; 42 align-items: center; 43 height: 50px; 44 h2, 45 button { 46 margin-right: 16px; 47 } 48`; 49 50export default Random; 51

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

投稿2020/01/09 14:47

gentamura

総合スコア406

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

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

whoiwhoi

2020/01/10 00:35

ご回答いただきありがとうござました。希望通りの挙動になりました。再レンダリングの影響を受けさせたくないものを親へ移すということですね。とても参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問