mirror of
https://github.com/rive-app/rive-react.git
synced 2026-03-13 08:22:30 +08:00
Compare commits
4 Commits
v4.27.1
...
resizeExam
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25afe7d77e | ||
|
|
258270b4fc | ||
|
|
41962ef864 | ||
|
|
c69fffa5cf |
32
examples/resize-test/README.md
Normal file
32
examples/resize-test/README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# To run
|
||||||
|
|
||||||
|
This is a basic showcase of a resize issue we have, to test this locally with rive-react changes
|
||||||
|
|
||||||
|
1. run `npm start`
|
||||||
|
2. run `npm run build` for the rive-react project
|
||||||
|
|
||||||
|
If you want to also test local wasm changes:
|
||||||
|
|
||||||
|
1. update `rive-react`/package.json to a locally checked out version of rive-wasm's canvas_single
|
||||||
|
`"@rive-app/canvas": "../rive-wasm/js/npm/canvas_single",`
|
||||||
|
2. cd to `rive-wasm/js` & run `npm run dev` (keep this going as it will watch for changes)
|
||||||
|
3. run `npm start`
|
||||||
|
4. run `npm run build` for the rive-react project
|
||||||
|
|
||||||
|
|
||||||
|
# Resize issue:
|
||||||
|
|
||||||
|
update parameters in `utils.ts` to see this for yourself.
|
||||||
|
|
||||||
|
Resizing from window.resize
|
||||||
|
- bottom animation moves slower than rest
|
||||||
|
- cannot deal with the animations container resizing, unless its linked to the window resizing
|
||||||
|
Resizing from ResizeObserver
|
||||||
|
- all animations move together super smooth when resizing
|
||||||
|
- top two animations flicker to white (blank canvas) when resizing
|
||||||
|
Resizing form ResizeObserver - throttled (current default)
|
||||||
|
- all animations move "together"
|
||||||
|
- resizing looks pretty smooth, but everything lags behind a bit.
|
||||||
|
|
||||||
|
# Other issues
|
||||||
|
its also very slow resizing when dev tools is open, its fine when closed though.
|
||||||
36
examples/resize-test/package.json
Normal file
36
examples/resize-test/package.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "basic-with-hook",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@testing-library/jest-dom": "^5.13.0",
|
||||||
|
"@testing-library/react": "^11.2.7",
|
||||||
|
"@testing-library/user-event": "^12.8.3",
|
||||||
|
"react": "file:../../node_modules/react",
|
||||||
|
"react-dom": "^17.0.2",
|
||||||
|
"react-scripts": "4.0.3",
|
||||||
|
"rive-react": "file:../..",
|
||||||
|
"web-vitals": "^1.1.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "SKIP_PREFLIGHT_CHECK=true react-scripts start"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"extends": [
|
||||||
|
"react-app",
|
||||||
|
"react-app/jest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"browserslist": {
|
||||||
|
"production": [
|
||||||
|
">0.2%",
|
||||||
|
"not dead",
|
||||||
|
"not op_mini all"
|
||||||
|
],
|
||||||
|
"development": [
|
||||||
|
"last 1 chrome version",
|
||||||
|
"last 1 firefox version",
|
||||||
|
"last 1 safari version"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
17
examples/resize-test/public/index.html
Normal file
17
examples/resize-test/public/index.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Web site created using create-react-app"
|
||||||
|
/>
|
||||||
|
<title>Rive React - Basic with Hook</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
examples/resize-test/public/magic-ball.riv
Normal file
BIN
examples/resize-test/public/magic-ball.riv
Normal file
Binary file not shown.
BIN
examples/resize-test/public/poison-loader.riv
Normal file
BIN
examples/resize-test/public/poison-loader.riv
Normal file
Binary file not shown.
30
examples/resize-test/src/App.js
Normal file
30
examples/resize-test/src/App.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { useRive } from 'rive-react';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const params = {
|
||||||
|
src: 'poison-loader.riv',
|
||||||
|
autoplay: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { RiveComponent: RiveComponentBasic } = useRive(params);
|
||||||
|
const { RiveComponent: RiveComponentBasic2 } = useRive(params);
|
||||||
|
const { RiveComponent: RiveComponentBasic3 } = useRive(params);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style={{ width: '100%' }}>
|
||||||
|
<div style={{ height: '300px', width: '100%' }}>
|
||||||
|
<RiveComponentBasic />
|
||||||
|
</div>
|
||||||
|
<div style={{ height: '300px', width: '100%' }}>
|
||||||
|
<RiveComponentBasic2 />
|
||||||
|
</div>
|
||||||
|
<div style={{ height: '300px', width: '100%' }}>
|
||||||
|
<RiveComponentBasic3 />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
10
examples/resize-test/src/index.js
Normal file
10
examples/resize-test/src/index.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>,
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { Rive, StateMachineInput } from '@rive-app/canvas';
|
import { EventType, Rive, StateMachineInput } from '@rive-app/canvas';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom hook for fetching a stateMachine input from a rive file.
|
* Custom hook for fetching a stateMachine input from a rive file.
|
||||||
@@ -18,21 +18,33 @@ export default function useStateMachineInput(
|
|||||||
const [input, setInput] = useState<StateMachineInput | null>(null);
|
const [input, setInput] = useState<StateMachineInput | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!rive || !stateMachineName || !inputName) {
|
function setStateMachineInput() {
|
||||||
setInput(null);
|
if (!rive || !stateMachineName || !inputName) {
|
||||||
}
|
setInput(null);
|
||||||
|
|
||||||
if (rive && stateMachineName && inputName) {
|
|
||||||
const inputs = rive.stateMachineInputs(stateMachineName);
|
|
||||||
if (inputs) {
|
|
||||||
const selectedInput = inputs.find((input) => input.name === inputName);
|
|
||||||
if (initialValue !== undefined && selectedInput) {
|
|
||||||
selectedInput.value = initialValue;
|
|
||||||
}
|
|
||||||
setInput(selectedInput || null);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
setInput(null);
|
if (rive && stateMachineName && inputName) {
|
||||||
|
const inputs = rive.stateMachineInputs(stateMachineName);
|
||||||
|
if (inputs) {
|
||||||
|
const selectedInput = inputs.find(
|
||||||
|
(input) => input.name === inputName
|
||||||
|
);
|
||||||
|
if (initialValue !== undefined && selectedInput) {
|
||||||
|
selectedInput.value = initialValue;
|
||||||
|
}
|
||||||
|
setInput(selectedInput || null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setInput(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setStateMachineInput();
|
||||||
|
if (rive) {
|
||||||
|
rive.on(EventType.Play, () => {
|
||||||
|
// Check if the component/canvas is mounted before setting state to avoid setState
|
||||||
|
// on an unmounted component in some rare cases
|
||||||
|
setStateMachineInput();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [rive]);
|
}, [rive]);
|
||||||
|
|
||||||
|
|||||||
48
src/utils.ts
48
src/utils.ts
@@ -8,8 +8,20 @@ class FakeResizeObserver {
|
|||||||
disconnect() {}
|
disconnect() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function throttle(f: Function, delay: number) {
|
||||||
|
let timer = 0;
|
||||||
|
return function (this: Function, ...args: any) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => f.apply(this, args), delay) as unknown as number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const MyResizeObserver = globalThis.ResizeObserver || FakeResizeObserver;
|
const MyResizeObserver = globalThis.ResizeObserver || FakeResizeObserver;
|
||||||
const hasResizeObserver = globalThis.ResizeObserver !== undefined;
|
const hasResizeObserver = globalThis.ResizeObserver !== undefined;
|
||||||
|
const preferResizeObserver = true;
|
||||||
|
const throttleResizeObserver = true;
|
||||||
|
const useResizeObserver = hasResizeObserver && preferResizeObserver;
|
||||||
|
const useWindowListener = !useResizeObserver;
|
||||||
|
|
||||||
export function useSize(
|
export function useSize(
|
||||||
containerRef: React.MutableRefObject<HTMLElement | null>
|
containerRef: React.MutableRefObject<HTMLElement | null>
|
||||||
@@ -29,32 +41,48 @@ export function useSize(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!hasResizeObserver) {
|
if (useWindowListener) {
|
||||||
// only pay attention to window size changes when we do not have the resizeObserver (IE only)
|
// only pay attention to window size changes when we do not have the resizeObserver (IE only)
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
handleResize();
|
handleResize();
|
||||||
|
window.addEventListener('resize', handleResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => window.removeEventListener('resize', handleResize);
|
return () => window.removeEventListener('resize', handleResize);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const observer = useRef(
|
const observer = useRef(
|
||||||
new MyResizeObserver((entries) => {
|
new MyResizeObserver(
|
||||||
setSize({
|
throttleResizeObserver
|
||||||
width: entries[entries.length - 1].contentRect.width,
|
? throttle((entries: any) => {
|
||||||
height: entries[entries.length - 1].contentRect.height,
|
if (useResizeObserver) {
|
||||||
});
|
setSize({
|
||||||
})
|
width: entries[entries.length - 1].contentRect.width,
|
||||||
|
height: entries[entries.length - 1].contentRect.height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 16)
|
||||||
|
: (entries: any) => {
|
||||||
|
if (useResizeObserver) {
|
||||||
|
setSize({
|
||||||
|
width: entries[entries.length - 1].contentRect.width,
|
||||||
|
height: entries[entries.length - 1].contentRect.height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const current = observer.current;
|
const current = observer.current;
|
||||||
if (containerRef.current) {
|
if (containerRef.current && useResizeObserver) {
|
||||||
current.observe(containerRef.current);
|
current.observe(containerRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
current.disconnect();
|
current.disconnect();
|
||||||
|
if (containerRef.current && useResizeObserver) {
|
||||||
|
current.unobserve(containerRef.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, [containerRef, observer]);
|
}, [containerRef, observer]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user