概要
現在、React + Pusherを利用したリアルタイムな機能の実装をしています。
具体的には、react-rndを使用したGUI操作を、Puhserを利用したWebSocket通信で別端末でもリアルタイムに変化させるというものです。
UIのイメージとしてはコンポーネント(react-rnd)の追加ボタンがあり、それを押すとコンポーネント(react-rnd)が追加され、GUIでの拡大縮小や移動ができるというイメージです。
コンポーネントの追加をリアルタイムで同期することは出来たのですが、移動と拡大縮小が中々うまいこといきません。
ロジックとしては、移動の際はx・y、拡大縮小の際はwidth・heitghtをidと一緒に送信し、受け取り側ではsetStickies
でstikies
の中身を、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
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。