react-native-ui-kitten
react-native-ui-kitten copied to clipboard
On iOS app crashes with the message "Got unexpected undefined"
π Bug Report
The bug seems to occur only on iOS on one app of mine with a very confusing behavior.
To Reproduce
Steps to reproduce the behavior: On my app:
- navigate to a screen containing a Select component ;
- open the Select popover (no need to select another item) ;
- navigate to next screen ;
- go back to first screen.
App crashes in release mode / Red screens in debug mode with the message "Got unexpected undefined" pointing to measureSelf function in "node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js".
If you don't open the Select popover there is no crash.
A quick session with Flipper shows that measureSelf passes "null" in the "node" variable. It seems to be a problem about the Select component keeping reacting to system events after being unmounted... Adding a setTimeout() does not solve anything. I'm fixing it with a patch adding a null check on the node variable before calling measureInWindow(). I'll work on a repro and a PR as soon as possible.
Expected behavior
App doesn't crash :)
Link to runnable example or repository (highly encouraged)
I'll try to take time to produce one later.
UI Kitten and Eva version
Package | Version |
---|---|
@eva-design/eva | 2.1.1 |
@ui-kitten/components | 5.1.2 |
Environment information
OS: macOS 13.5.2
CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Binaries:
Node: 16.20.2 - ~/.nvm/versions/node/v16.20.2/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 8.19.4 - ~/Sources/Adoria/adoria-start/node_modules/.bin/npm
pnpm: 8.9.0 - /usr/local/bin/pnpm
Watchman: 2023.08.28.00 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: DriverKit 23.0, iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0
IDEs:
Android Studio: 2022.2 AI-222.4459.24.2221.10121639
Xcode: 15.0/15A240d - /usr/bin/xcodebuild
npmPackages:
react: 18.2.0 => 18.2.0
react-native: 0.72.5 => 0.72.5
Got the same issue
Got the same issue when navigating from login screen to home screen. Using Layout as parent in home screen. Happening only for ios.
I'm strugling to produce a repro but I'll try again tomorrow. Hopefully I'll be able to submit a fix then.
While navigating some times i am getting "Got unexpected undefined" throwing this error. This is happening in iOS. Please help me out in fixing this.
@chinmay4github1987 One workaround:
const isFocused = useIsFocused();
{isFocused && (<Select ... />)}
This is not pretty and you might need some placeholder so that your interface does not glitch... But if you have more time, go for @psegalen solution.
T
@chinmay4github1987 One workaround:
const isFocused = useIsFocused(); {isFocused && (<Select ... />)}
This is not pretty and you might need some placeholder so that your interface does not glitch... But if you have more time, go for @psegalen solution.
It is happening during navigation means switching between screens
Got the same issue with Datepicker
I can't find a way to reproduce easily (and I can't publish my client's code), even by using Layout and playing with different things in navigation... :( I think I'll submit a PR anyway because I'm pretty sure we should not ask for the size of a component being null or undefined...
IsFocused workaround isn't supposedly working for me. I don't have a select component rather it happens on tab bar component. So is there a solution/workaround or are they ever going to merge this.
Has this issue been addressed?
Experiencing the same with @ui-kitten/components: 5.3.1
I am receiving the same issue. Version is js on "@ui-kitten/components": "^5.3.1" and "react-native": "^0.73.1"
Issue occurs while navigating between screens and I have spent a ton of time trying to narrow down the bug. :/
Basically produces: ERROR Error: Got unexpected undefined, js engine: hermes
Then trace gets to: .../node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js with code error spawn code ENOENT
Any help or workarounds? I am stuck :(
Experiencing the same issue with 5.3.1, it happens some time between navigations but not every time, really hard to narrow down what's really happening π€
Has anyone found a workaround or fix?
@GoDeepBlue you can patch UI Kitten with the code from my PR as a temporary solution until the PR is merged. For this specific problem, the fix is at line 78 in https://github.com/akveo/react-native-ui-kitten/pull/1790/files I have 2 apps on which this patch prevented the crash to be reported by crashlytics and sentry, one is patched with patch-package because it's a Yarn 1.x project, the other with yarn patch, both are ok now
Thank you @psegalen, I implemented the fix and seems to be working so far! You areπ₯ π
Thank you @psegalen, I implemented the fix and seems to be working so far! You areπ₯ π
Hey @GoDeepBlue , could you briefly explain how did you apply the fix? Is it by manually editing the UI Kitten library in node_modules folder?
I also need that fix. Can someone explain, please?
Hi @adrianlzx1996 and @brunomartins-com ! First of all: don't just edit directly the source files in node_modules because each time you'll do a dependencies install (through npm or yarn), your edition will be deleted. You need to create a patch, there are basically 2 ways to do that and it depends if you use yarn 2+ or not. For yarn 2+ you can use the built-in feature yarn patch, doc is there: https://yarnpkg.com/cli/patch For yarn 1.x or npm, you can use the "patch-package" devDependency, here is tutorial: https://dev.to/zhnedyalkow/the-easiest-way-to-patch-your-npm-package-4ece Anyway, for both tools the procedure is the same: once the tool is operational make your edition to the source code of your dependency in node_modules and launch the patch procedure, it will generate a patch (a file telling your dependencies manager that it needs to modify one dependency after its install and how to modify it)
Hi @adrianlzx1996 and @brunomartins-com ! First of all: don't just edit directly the source files in node_modules because each time you'll do a dependencies install (through npm or yarn), your edition will be deleted. You need to create a patch, there are basically 2 ways to do that and it depends if you use yarn 2+ or not. For yarn 2+ you can use the built-in feature yarn patch, doc is there: https://yarnpkg.com/cli/patch For yarn 1.x or npm, you can use the "patch-package" devDependency, here is tutorial: https://dev.to/zhnedyalkow/the-easiest-way-to-patch-your-npm-package-4ece Anyway, for both tools the procedure is the same: once the tool is operational make your edition to the source code of your dependency in node_modules and launch the patch procedure, it will generate a patch (a file telling your dependencies manager that it needs to modify one dependency after its install and how to modify it)
Hey @psegalen thanks for your advise and reply!
The solution is in measure.component.js to check for if (node):
const measureSelf = () => {
const node = (0, react_native_1.findNodeHandle)(ref.current);
//react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
if (node) {
react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
}
};
However, I guess either a new release is needed or a patch, but not too confident
For those using yarn patch or patch-package, here's the patch I'm using:
diff --git a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
index 02180f9..b51cca0 100644
--- a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
+++ b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
@@ -42,7 +42,7 @@ const MeasureElement = (props) => {
if (frame.origin.x < window.size.width) {
return frame;
}
- const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, frame.size.width, frame.size.height);
+ const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, Math.round(frame.size.width), Math.round(frame.size.height));
return bindToWindow(boundFrame, window);
};
const onUIManagerMeasure = (x, y, w, h) => {
@@ -51,13 +51,13 @@ const MeasureElement = (props) => {
}
else {
const originY = props.shouldUseTopInsets ? y + react_native_1.StatusBar.currentHeight || 0 : y;
- const frame = bindToWindow(new type_1.Frame(x, originY, w, h), type_1.Frame.window());
+ const frame = bindToWindow(new type_1.Frame(x, originY, Math.round(w), Math.round(h)), type_1.Frame.window());
props.onMeasure(frame);
}
};
const measureSelf = () => {
const node = (0, react_native_1.findNodeHandle)(ref.current);
- react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
+ if (node) react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
};
if (props.force) {
measureSelf();
+1 for patching with @jgillick @psegalen solution
tested within my current ongoing project, the patch from @jgillick works.
Project abandoned?
For those using yarn patch or patch-package, here's the patch I'm using:
diff --git a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js index 02180f9..b51cca0 100644 --- a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js +++ b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js @@ -42,7 +42,7 @@ const MeasureElement = (props) => { if (frame.origin.x < window.size.width) { return frame; } - const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, frame.size.width, frame.size.height); + const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, Math.round(frame.size.width), Math.round(frame.size.height)); return bindToWindow(boundFrame, window); }; const onUIManagerMeasure = (x, y, w, h) => { @@ -51,13 +51,13 @@ const MeasureElement = (props) => { } else { const originY = props.shouldUseTopInsets ? y + react_native_1.StatusBar.currentHeight || 0 : y; - const frame = bindToWindow(new type_1.Frame(x, originY, w, h), type_1.Frame.window()); + const frame = bindToWindow(new type_1.Frame(x, originY, Math.round(w), Math.round(h)), type_1.Frame.window()); props.onMeasure(frame); } }; const measureSelf = () => { const node = (0, react_native_1.findNodeHandle)(ref.current); - react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure); + if (node) react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure); }; if (props.force) { measureSelf();
The solution works!
when I run npx patch-package "@ui-kitten"
it gives an error, MODULE_NOT_FOUND
does the @ in the name affect the patch-package command?
Edit
I just learned that @ in a package name is indicating a namespace, and the package full name must be provided, so npx patch-package @ui-kitten/components
worked.
Here are the steps to fix the issue until patch is released (also fixes #1813):
- Install
patch-package
as dev dependency
npm install -D patch-package
- Create
patches/@ui-kitten+components+5.3.1.patch
file in your project's root directory with the following content:
diff --git a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
index 02180f9..c952313 100644
--- a/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
+++ b/node_modules/@ui-kitten/components/devsupport/components/measure/measure.component.js
@@ -36,13 +36,18 @@ const type_1 = require("./type");
* but `force` property may be used to measure any time it's needed.
* DON'T USE THIS FLAG IF THE COMPONENT RENDERS FIRST TIME OR YOU KNOW `onLayout` WILL BE CALLED.
*/
-const MeasureElement = (props) => {
+const MeasureElement = ({
+ force = false,
+ shouldUseTopInsets = false,
+ onMeasure,
+ children
+ }) => {
const ref = react_1.default.useRef();
const bindToWindow = (frame, window) => {
if (frame.origin.x < window.size.width) {
return frame;
}
- const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, frame.size.width, frame.size.height);
+ const boundFrame = new type_1.Frame(frame.origin.x - window.size.width, frame.origin.y, Math.round(frame.size.width), Math.round(frame.size.height));
return bindToWindow(boundFrame, window);
};
const onUIManagerMeasure = (x, y, w, h) => {
@@ -50,22 +55,19 @@ const MeasureElement = (props) => {
measureSelf();
}
else {
- const originY = props.shouldUseTopInsets ? y + react_native_1.StatusBar.currentHeight || 0 : y;
- const frame = bindToWindow(new type_1.Frame(x, originY, w, h), type_1.Frame.window());
- props.onMeasure(frame);
+ const originY = shouldUseTopInsets ? y + react_native_1.StatusBar.currentHeight || 0 : y;
+ const frame = bindToWindow(new type_1.Frame(x, originY, Math.round(w), Math.round(h)), type_1.Frame.window());
+ onMeasure(frame);
}
};
const measureSelf = () => {
const node = (0, react_native_1.findNodeHandle)(ref.current);
- react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
+ if (node) react_native_1.UIManager.measureInWindow(node, onUIManagerMeasure);
};
- if (props.force) {
+ if (force) {
measureSelf();
}
- return react_1.default.cloneElement(props.children, { ref, onLayout: measureSelf });
+ return react_1.default.cloneElement(children, { ref, onLayout: measureSelf });
};
exports.MeasureElement = MeasureElement;
-exports.MeasureElement.defaultProps = {
- shouldUseTopInsets: false,
-};
//# sourceMappingURL=measure.component.js.map
\ No newline at end of file
- Reinstall dependencies:
npm i