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

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

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

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

JavaScript

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

React.js

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

Q&A

解決済

1回答

1249閲覧

React + Pusherを用いたリアルタイム通信におけるsetStateでの再レンダーがかからない問題

退会済みユーザー

退会済みユーザー

総合スコア0

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

JavaScript

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

React.js

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

0グッド

0クリップ

投稿2020/02/15 14:33

概要

現在、React + Pusherを利用したリアルタイムな機能の実装をしています。
具体的には、react-rndを使用したGUI操作を、Puhserを利用したWebSocket通信で別端末でもリアルタイムに変化させるというものです。
UIのイメージとしてはコンポーネント(react-rnd)の追加ボタンがあり、それを押すとコンポーネント(react-rnd)が追加され、GUIでの拡大縮小や移動ができるというイメージです。
コンポーネントの追加をリアルタイムで同期することは出来たのですが、移動と拡大縮小が中々うまいこといきません。
ロジックとしては、移動の際はx・y、拡大縮小の際はwidth・heitghtをidと一緒に送信し、受け取り側ではsetStickiesstikiesの中身を、Pusherから受け取ったデータ(id、x・y、width・heght)で更新するというものです。idはどのコンポーネントが変更されたかということを特定できる一意な値です。
データの受け取りやWebSocket通信が正常に行われていることはconsole.logで確認済みです。
ロジックに関しても追加が出来ているということから特に問題はなさそうです。
つまり、setStickiesでのstateの更新がうまく行われておらず、stateの変更による再レンダーがかかっていないようです。
該当の部分はuseEffect内の

channel.bind('App\Events\StickyResized', data => {...}

の中に記述されている下記の部分です。

let newStickies = [...stickies] const index = stickies.findIndex(sticky => sticky.id === data.sticky.id) newStickies[index].width = data.sticky.width newStickies[index].height = data.sticky.height console.log(newStickies[index]) setStickies(newStickies)

自分なりに色々試しましたが、解決せず…。
どなたか解決方法のご教授お願い致します。

更新したいstateの中身はこんな感じです。

{stickies: Array(2)} stickies: Array(2) 0: id: 5 board_id: "n56t47gm" user_id: "a" x: 157 y: 214 width: 180 height: 180 body: "" created_at: "2020-02-15 13:24:45" updated_at: "2020-02-15 13:39:14" __proto__: Object 1: id: 6 board_id: "n56t47gm" user_id: "a" x: 342 y: 93 width: 180 height: 180 body: "" created_at: "2020-02-15 13:48:01" updated_at: "2020-02-15 13:48:03" __proto__: Object length: 2 __proto__: Array(0) __proto__: Object

該当のコード

JavaScript

1import React, { useState, useEffect } from "react" 2 3import styled from 'styled-components' 4import { createStyles, makeStyles } from '@material-ui/core/styles' 5 6import { Rnd } from "react-rnd" 7 8import Footer from '../Footer' 9import Sticky from './../../models/Sticky' 10import User from './../../models/User' 11import Board from './../../models/Board' 12 13import Pusher from 'pusher-js' 14import * as pusherConfig from './../../config/pusher' 15 16// Pusherの設定 17Pusher.logToConsole = true 18const pusher = new Pusher(pusherConfig.key, { 19 cluster: pusherConfig.cluster, 20 forceTLS: false 21}) 22const useStyles = makeStyles(theme => createStyles({ 23 toolbar: { 24 ...theme.mixins.toolbar 25 }, 26})) 27 28const style = { 29 display: "flex", 30 alignItems: "center", 31 justifyContent: "center", 32 background: "#f0f0f0", 33 padding: "18px", 34 background: 35 "linear-gradient(135deg, transparent 0px, #ccc 0) top left, linear-gradient(225deg, transparent 20px, #ccc 0) top right, linear-gradient(315deg, transparent 0px, #ccc 0) bottom right, linear-gradient(45deg, transparent 0px, #ccc 0) bottom left", 36 backgroundSize: '51% 51%', 37 backgroundRepeat: 'no-repeat' 38} 39 40const StickyBoard = () => { 41 const classes = useStyles() 42 const [stickies, setStickies] = useState([]) 43 let isChanged = true 44 45 useEffect(() => { 46 const channelName = 'sticky-' + Board.getBoardID() 47 const channel = pusher.subscribe(channelName) 48 49 // 付箋を追加した時 50 channel.bind('App\Events\StickyAdded', data => { 51 setStickies([...stickies, data.sticky]) 52 }) 53 // 付箋を編集した時 54 channel.bind('App\Events\StickyEdited', data => { 55 setStickies([...stickies, data.sticky]) 56 }) 57 // 付箋を動かした時 58 channel.bind('App\Events\StickyMoved', data => { 59 let newStickies = [...stickies] 60 const index = stickies.findIndex(sticky => sticky.id === data.sticky.id) 61 newStickies[index].x = data.sticky.x 62 newStickies[index].x = data.sticky.y 63 console.log(newStickies[index]) 64 setStickies(newStickies) 65 }) 66 // 付箋をリサイズした時 67 channel.bind('App\Events\StickyResized', data => { 68 let newStickies = [...stickies] 69 const index = stickies.findIndex(sticky => sticky.id === data.sticky.id) 70 newStickies[index].width = data.sticky.width 71 newStickies[index].height = data.sticky.height 72 console.log(newStickies[index]) 73 setStickies(newStickies) 74 }) 75 76 return () => { 77 channel.unbind('App\Events\StickyAdded') 78 channel.unbind('App\Events\StickyEdited') 79 channel.unbind('App\Events\StickyMoved') 80 channel.unbind('App\Events\StickyResized') 81 } 82 }, [stickies, setStickies]) 83 84 useEffect(() => { 85 const token = JSON.parse(User.get('token')).token 86 const boardID = Board.getBoardID() 87 88 if (token) { 89 Sticky.get(token, boardID) 90 .then(res => { 91 console.log(res.data) 92 setStickies(res.data.stickies) 93 }) 94 .catch(e => { 95 console.log(e) 96 }) 97 } 98 }, [isChanged]) 99 100 const addSticky = () => { 101 const token = JSON.parse(User.get('token')).token 102 const boardID = Board.getBoardID() 103 if (token) { 104 Sticky.add(token, boardID) 105 .catch(e => { 106 console.log(e) 107 }) 108 } 109 } 110 const handleEdit = (e) => { 111 //Sticky.edit(token) 112 } 113 const handleMove = (id) => { 114 const token = JSON.parse(User.get('token')).token 115 return (e, data) => { 116 Sticky.move(token, id, data.x, data.y) 117 .catch(e => { 118 console.log(e) 119 }) 120 } 121 } 122 const handleResize = (id) => { 123 const token = JSON.parse(User.get('token')).token 124 return (e, dir, ref) => { 125 Sticky.resize(token, id, ref.style.width.slice(0, -2), ref.style.height.slice(0, -2)) 126 .catch(e => { 127 console.log(e) 128 }) 129 } 130 } 131 132 return ( 133 <> 134 <div className={classes.toolbar} /> 135 <p><button onClick={addSticky}>付箋を追加</button></p> 136 {stickies.map((sticky, i) => ( 137 <Rnd 138 key={i} 139 style={style} 140 maxWidth={220} 141 maxHeight={220} 142 minWidth={140} 143 minHeight={140} 144 default={{ 145 x: sticky.x, 146 y: sticky.y, 147 width: sticky.width, 148 height: sticky.height 149 }} 150 onDragStop={handleMove(sticky.id)} 151 onResizeStop={handleResize(sticky.id)} 152 > 153 <Textarea onMouseDown={e => e.stopPropagation()}></Textarea> 154 </Rnd> 155 ))} 156 <Footer /> 157 </> 158 ) 159} 160 161const Textarea = styled.textarea` 162 resize: none; 163 width: 100%; 164 height: 100%; 165 font-size: 1.3em; 166` 167 168export default StickyBoard

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

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

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

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

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

guest

回答1

0

ベストアンサー

stateの変更による再レンダーがかかっていないようです。

デバッグしていないので確実ではないですが、このコードだとそもそも position や width / height のスタイルがあたっていない気がしましたmm
state の x, y 等を一旦決め打ちにして位置が正しくセットされるのか確認したい気がします。
とともに、もしそれが原因であれば JSX に渡す style をコンポーネント外で定数にするのではなく、state を使って動的にする必要があるかと思いましたmm

投稿2020/02/16 03:20

編集2020/02/16 03:21
unhappychoice

総合スコア1531

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問