Switch timer slider to a controlled component to have its value sync

This commit is contained in:
zikaeroh 2020-05-23 21:44:08 -07:00
parent 800ce1cbad
commit e12cf989fc
1 changed files with 25 additions and 19 deletions

View File

@ -168,51 +168,57 @@ const Header = ({ send, state, pState, pTeam }: GameViewProps) => {
const sliderMarks = range(30, 301, 30).map((v) => ({ value: v })); const sliderMarks = range(30, 301, 30).map((v) => ({ value: v }));
interface TimerSliderProps { interface TimerSliderProps {
id: string; version: number;
timer: StateTimer; timer: StateTimer;
onCommit: (value: number) => void; onCommit: (value: number) => void;
} }
const TimerSlider = ({ timer, onCommit, id }: TimerSliderProps) => { interface TimerValue {
// Keep around the original value when this component is created. version: number;
// This prevents React from complaining about the defaultValue turnTime: number;
// changing when the overall state changes. }
const defaultValue = React.useRef(timer.turnTime);
const [value, setValue] = React.useState(timer.turnTime); const TimerSlider = ({ version, timer, onCommit }: TimerSliderProps) => {
const [value, setValue] = React.useState<TimerValue>({ version, turnTime: timer.turnTime });
React.useEffect(() => {
if (version !== value.version) {
setValue({ version, turnTime: timer.turnTime });
}
}, [version, value.version, timer.turnTime]);
const valueStr = React.useMemo(() => { const valueStr = React.useMemo(() => {
switch (value) { const turnTime = value.turnTime;
switch (turnTime) {
case 30: case 30:
return '30 seconds'; return '30 seconds';
case 60: case 60:
return '60 seconds'; return '60 seconds';
default: default:
if (value % 60 === 0) { if (turnTime % 60 === 0) {
return `${value / 60} minutes`; return `${turnTime / 60} minutes`;
} }
return `${(value / 60).toFixed(1)} minutes`; return `${(turnTime / 60).toFixed(1)} minutes`;
} }
}, [value]); }, [value.turnTime]);
return ( return (
<> <>
<Typography id={id} gutterBottom> <Typography id="timer-slider" gutterBottom>
Timer: {valueStr} Timer: {valueStr}
</Typography> </Typography>
<Slider <Slider
style={{ color: orange[500] }} style={{ color: orange[500] }}
aria-labelledby={id} aria-labelledby="timer-slider"
value={value.turnTime}
marks={sliderMarks} marks={sliderMarks}
defaultValue={defaultValue.current}
step={null} step={null}
min={sliderMarks[0].value} min={sliderMarks[0].value}
max={sliderMarks[sliderMarks.length - 1].value} max={sliderMarks[sliderMarks.length - 1].value}
onChange={(_e, v) => { onChange={(_e, v) => {
assertTrue(!isArray(v)); assertTrue(!isArray(v));
if (v !== value) { setValue({ version: value.version, turnTime: v });
setValue(v);
}
}} }}
onChangeCommitted={(_e, v) => { onChangeCommitted={(_e, v) => {
assertTrue(!isArray(v)); assertTrue(!isArray(v));
@ -382,7 +388,7 @@ const Sidebar = ({ send, state, pState, pTeam }: GameViewProps) => {
</div> </div>
{!isDefined(state.timer) ? null : ( {!isDefined(state.timer) ? null : (
<div style={{ textAlign: 'left', marginTop: '1rem' }}> <div style={{ textAlign: 'left', marginTop: '1rem' }}>
<TimerSlider id="timer-slider" timer={state.timer} onCommit={send.changeTurnTime} /> <TimerSlider version={state.version} timer={state.timer} onCommit={send.changeTurnTime} />
</div> </div>
)} )}
</> </>