我有一个反应应用程序,它在感应到 API 命中时传递给SlotMachine
组件(使用 Pusher 进行发布-订阅)。
rotate()
但是,每个 API hit应该只执行一次,正如您在我的输出中看到的那样,它调用rotate()
了多次,并且每次之前 props 都发生了变化。但是道具在控制台中看起来是一样的,并且在第一个之后没有更多的 API 命中(我正在使用 Postman 触发)。
有什么理由让我的道具发生如此大的变化?我对钩子或道具有什么不明白的地方?另外,为什么我的旋转函数会不断被调用,除非在第一次 API 命中之后?
应用程序:
import React, { useState, useEffect } from 'react'
import { render } from 'react-dom'
import Pusher from 'pusher-js'
import SlotMachine from './components/SlotMachine'
const App = () => {
const [ slots, setSlots ] = useState([]);
const [ apiHit, setApiHit ] = useState(false);
const pusher = new Pusher('XXXXXXX', {
cluster: 'XXX',
encrypted: true
});
const channel = pusher.subscribe('my-channel');
channel.bind('my-event', data => {
console.log(`Got data from pusher ${data}`);
setSlots(data);
setApiHit(true);
});
return(
<div>
<SlotMachine slots={slots} apiHit={apiHit}/>
</div>
);
};
render(<App />, document.getElementById('root'));
老虎机:
import React, { useEffect, useRef, useState } from 'react'
import './slots.css'
function rnd(min, max) {
return Math.floor(Math.random() * (max - min)) + min
}
const SlotMachine = (props) => {
const ringElements = useRef();
const [manual, setManual] = useState(true);
const [rings, updateRings] = useState([]);
const [ slots, setSlots ] = useState([]);
const slotMap = {
0: 72,
1: 144,
2: 216,
3: 288,
4: 360
};
useEffect(()=>{
console.log(' --- props change --- ');
console.log(props);
setSlots( slots => props.slots );
if(props.slots !== undefined && props.apiHit === true ) {
setManual(manual => false);
rotate();
setManual(true);
}
}, [props.slots, props.apiHit]);
//need to store previous to get accurate measure
const rotate = () => {
console.log(`---ROTATE---`);
rings.forEach((el, i) => {
let obj = el; //should be an obj
console.log(obj);
let prev = null;
if (obj.prev !== null) { prev = obj.prev; } //update prev if not first time
console.log(`Prev is ${prev}`);
let element = obj.ringElement; //should be the ring itself
//let obj = rings[i];
console.log(element);
//get the slots it needs to move to
let move = manual && !props.apiHit ? slotMap[rnd(0,4)] : slotMap[slots[i]];
console.log(`move: ${move}`);
let diff = Math.abs(prev - move);
console.log(`The diff is ${diff}`);
//take the previous and the move and figure out "difference", be sure to add that difference to the spin
let res = move + (360 * rnd(3,6));
//let res = move //+ (360 * rnd(3,6)); //randomly spin should end up back at same spot no matter what
console.log(`rotateX(${res}deg) for ring${i}`);
element.style.transform = `rotateX(${res}deg)`;
obj.prev = move;
//rings[i] = obj;// update proper object in state
rings[i] = obj;
updateRings( rings );
});
}
//when first mounts
useEffect(() => {
console.log('component did mount');
Array.from(ringElements.current.children).forEach((el, i) => {
console.log(`elements in ring: ${el}`);
let obj = {}
obj.ringElement = el
obj.prev = null
updateRings(rings => [...rings, obj])
// updateRings(rings => [...rings, el]);
});
}, []);
return(
<div>
<div className="slots">
<div className="rings" ref={ringElements}>
<div className="ring">
<div className="slot" id="0">0</div>
<div className="slot" id="1">1</div>
<div className="slot" id="2">2</div>
<div className="slot" id="3">3</div>
<div className="slot" id="4">4</div>
</div>
<div className="ring">
<div className="slot" id="0">0</div>
<div className="slot" id="1">1</div>
<div className="slot" id="2">2</div>
<div className="slot" id="3">3</div>
<div className="slot" id="4">4</div>
</div>
<div className="ring">
<div className="slot" id="0">0</div>
<div className="slot" id="1">1</div>
<div className="slot" id="2">2</div>
<div className="slot" id="3">3</div>
<div className="slot" id="4">4</div>
</div>
</div>
</div>
<button className="spin-button" onClick={() => { setManual(true); rotate(); } }>SPIN</button>
</div>
);
}
export default SlotMachine
输出:
初始 API 命中(按预期工作,仅触发一次 Rotate()
Got data from pusher 3,1,3 . <-- new API data recieved
55 **--- props change ---**
56 {slots: Array(3), apiHit: false}
55 **--- props change ---**is
56 {slots: Array(3), apiHit: true}
71 **---ROTATE---**
75 {ringElement: div.ring, prev: null}
83 Prev is null
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 288
96 rotateX(2088deg) for ring0
75 {ringElement: div.ring, prev: null}
83 Prev is null
87 <div class="ring" style="transform: rotateX(1224deg);">…</div>
90 move: 144
92 The diff is 144
96 rotateX(1224deg) for ring1
75 {ringElement: div.ring, prev: null}
83 Prev is null
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 288
96 rotateX(2088deg) for ring2
随后的 API 命中会执行多次旋转调用,并在每次调用之前显示 props 的变化。
Got data from pusher 3,0,1 . <-- new API hit
55 --- props change ---
56 {slots: Array(3), apiHit: true}
71 ---ROTATE---
75 {ringElement: div.ring, prev: 288}
83 Prev is 288
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 0
96 rotateX(1368deg) for ring0
75 {ringElement: div.ring, prev: 144}
83 Prev is 144
87 <div class="ring" style="transform: rotateX(1224deg);">…</div>
90 move: 144
92 The diff is 0
96 rotateX(1584deg) for ring1
75 {ringElement: div.ring, prev: 288}
83 Prev is 288
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 0
96 rotateX(2088deg) for ring2
VM12097 index.js:39 Got data from pusher 3,0,1 . <-- **same** API hit but recorded again????
55 --- props change ---
56 {slots: Array(3), apiHit: true}apiHit: trueslots: (3) [3, 0, 1]__proto__: Object
71 ---ROTATE---
75 {ringElement: div.ring, prev: 288}
83 Prev is 288
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 0
96 rotateX(1368deg) for ring0
75 {ringElement: div.ring, prev: 144}
83 Prev is 144
87 <div class="ring" style="transform: rotateX(1224deg);">…</div>
90 move: 72
92 The diff is 72
96 rotateX(1152deg) for ring1
75 {ringElement: div.ring, prev: 288}
83 Prev is 288
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 144
92 The diff is 144
96 rotateX(1584deg) for ring2
VM12097 index.js:39 Got data from pusher 3,0,1
55 --- props change ---
56 {slots: Array(3), apiHit: true}
71 ---ROTATE---
75 {ringElement: div.ring, prev: 288}
83 Prev is 288
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 288
92 The diff is 0
96 rotateX(1728deg) for ring0
75 {ringElement: div.ring, prev: 72}
83 Prev is 72
87 <div class="ring" style="transform: rotateX(1224deg);">…</div>
90 move: 72
92 The diff is 0
96 rotateX(1152deg) for ring1
75 {ringElement: div.ring, prev: 144}
83 Prev is 144
87 <div class="ring" style="transform: rotateX(2088deg);">…</div>
90 move: 144
92 The diff is 0
96 rotateX(1224deg) for ring2