Describe the bug
Attempting to use action
from @storybook/addon-actions
causes console errors and the output doesn't match the docs, possibly due to how the React Synthetic Events are being serialized.
To Reproduce
create-react-app sbtemp
cd sbtemp
npx -p @storybook/cli sb init
yarn storybook
Then the demo button in the "Button" "with Text" story is clicked. Google Chrome gives a deprecation warning:
[Deprecation] 'window.webkitStorageInfo' is deprecated. Please use 'navigator.webkitTemporaryStorage' or 'navigator.webkitPersistentStorage' instead.
The output in the Storybook Actions addon panel doesn't match the output shown in the docs, reading as clicked: [Class]
instead of the clicked: ["[SyntheticEvent]", null, "[SyntheticEvent]"]
shown on https://storybook.js.org/docs/addons/introduction/
clicked: [Class]
0: Class
_dispatchInstances: Object
_dispatchListeners: function action()
_targetInst: Object
altKey: false
bubbles: true
button: 0
buttons: 0
cancelable: true
clientX: 82
clientY: 32
ctrlKey: false
currentTarget: HTMLButtonElement
defaultPrevented: false
detail: 1
dispatchConfig: Object
eventPhase: 3
getModifierState: function modifierStateGetter()
isDefaultPrevented: function functionThatReturnsFalse()
isPropagationStopped: function functionThatReturnsFalse()
isTrusted: true
metaKey: false
movementX: 0
movementY: 0
nativeEvent: MouseEvent
pageX: 82
pageY: 32
relatedTarget: null
screenX: 292
screenY: 185
shiftKey: false
target: HTMLButtonElement
timeStamp: 266833.9550000001
type: "click"
view: Window
Additionally, if react
and react-dom
is downgraded to 16.3.2
(the version I was using when I encountered the issue), there is also another console error:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're adding a new property in the synthetic event object. The property is never released. See https://fb.me/react-event-pooling for more information.
Expected behavior
No console errors or warnings, and for the Action panel to match the docs.
System:
Additional context
I was unable to recreate this additional error, but in my own setup I also saw telejson
/ JSON.stringify
choke on something (Date
-related?) with an error of Uncaught TypeError: toISOString is not a function
Im facing similar issue.
Sounds like something weird is going on. Any chance you can provide a repro?
@shilman I gave some example CLI commands to reproduce it, is there a better repro format or service to use?
I tested it again just now and got the same issue (Chrome 73.0.3683.103, Storybook 5.0.10, Node v11.14.0)
@vdh Sorry I missed that. I'll check it out!
Ok, I can reproduce. Marking this as a bug & will gratefully accept any PRs to fix! 馃檱
Aside from the warning, what would be the desired behavior?
@kohakukun Not causing warnings/errors, and consistent behaviour with what is described by the docs. So either update the behaviour to match the docs or vice versa. Compatibility with React 16.3.2 would be nice but I would understand if that's not possible. (I've updated React so this is no longer relevant)
I assume the Uncaught TypeError: toISOString is not a function
error I was encountering was either fallout from the event handling issue or a problem in my own code, which should hopefully be fixed once the main issue is addressed.
i'm actually hitting the Uncaught TypeError: toISOString is not a function
after update, and cannot find an issue aside from this issue, so i'm hoping it is not your code and is instead part of this issue.
I'm using @storybook/react-native
and @storybook/react-native-server
and having the same issue as described above.
I'm also getting the synthetic event is used for performance reasons error described above. I haven't updated react-dom.
storybook/stories/index.js
)storiesOf("Button", module)
.addDecorator(getStory => <CenterView>{getStory()}</CenterView>)
.add("with text", () => (
<Button onPress={action("clicked-text")}>
<Text>Hello Button</Text>
</Button>
))
The error below recurses
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're %s `%s` on a released/nullified synthetic event. %s. If you must keep the original synthetic event around, use event.persist(). See https://fb.me/react-event-pooling for more information., accessing the property, target, This is set to null
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:619:8 in warningWithoutStack
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:1577:10 in warn
- node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js:1569:9 in get$$1
* [native code]:null in stringify
- node_modules/@storybook/react-native/node_modules/@storybook/channel-websocket/dist/index.js:67:46 in sendNow
- node_modules/@storybook/react-native/node_modules/@storybook/channel-websocket/dist/index.js:56:21 in send
- node_modules/@storybook/channels/dist/index.js:126:32 in handler
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:152:14 in _callTimer
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:200:17 in _callImmediatesPass
- node_modules/react-native/Libraries/Core/Timers/JSTimers.js:464:30 in callImmediates
* [native code]:null in callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:320:6 in __callImmediates
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:135:6 in <unknown>
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:297:10 in __guard
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:134:17 in flushedQueue
* [native code]:null in flushedQueue
* [native code]:null in callFunctionReturnFlushedQueue
@storybook/react-native-server
)@storybook/react-native
)
"scripts": {
"android": "expo start --android",
"build": "yarn run build:components",
"build:components": "webpack --config ./webpack.components.js",
"eject": "expo eject",
"expo": "expo start",
"ios": "expo start --ios",
"start": "npm-run-all --parallel expo storybook",
"storybook": "start-storybook -p 7007"
},
"dependencies": {
"@emotion/native": "^10.0.11",
"expo": "^32.0.0",
"native-base": "^2.12.1",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react-router": "^5.0.0"
},
"devDependencies": {
"@babel/preset-react": "^7.0.0",
"@emotion/core": "^10.0.10",
"@storybook/addon-actions": "^5.0.11",
"@storybook/addon-links": "^5.0.11",
"@storybook/addon-storysource": "^5.0.11",
"@storybook/addons": "^5.0.11",
"@storybook/react-native": "^5.0.11",
"@storybook/react-native-server": "5.1.0-alpha.7",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.5",
"babel-preset-expo": "^5.0.0",
"babel-runtime": "^6.26.0",
"duplicate-package-checker-webpack-plugin": "^3.0.0",
"emotion-theming": "^10.0.10",
"npm-run-all": "^4.1.5",
"prop-types": "^15.7.2",
"react-dom": "16.5.0",
"size-plugin": "^1.2.0",
"storybook-react-router": "^1.0.5",
"webpack-cli": "^3.3.2",
"webpack-node-externals": "^1.7.2"
},
import "@storybook/addon-actions/register";
import "@storybook/addon-links/register";
import "@storybook/addon-storysource/register";
import "@storybook/addon-ondevice-actions/register";
import "@storybook/addon-ondevice-links/register";
import "@storybook/addon-ondevice-storysource/register";
@alechp Can you open a separate issue? ondevice-actions
is a RN addon, and I'd like the RN guys to look at it, but I'm not sure it's the same issue.
@shilman Roger. New issue created here: https://github.com/storybooks/storybook/issues/6827
I'm getting the following error when I listen to click even on a button and pass it to actions:-
_ctx.js:18 Uncaught TypeError: toISOString is not a function
at String.toJSON (<anonymous>)
at Object.<anonymous> (_ctx.js:18)
at JSON.stringify (<anonymous>)
at Object.stringify (index.js:353)
at PostmsgTransport.push../node_modules/@storybook/channel-postmessage/dist/index.js.PostmsgTransport.send (index.js:43)
at handler (index.js:46)
at Channel.push../node_modules/@storybook/channels/dist/index.js.Channel.emit (index.js:55)
at action (action.js:32)
at HTMLUnknownElement.callCallback (react-dom.development.js:149)
at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
(anonymous) @ _ctx.js:18
stringify @ index.js:353
push../node_modules/@storybook/channel-postmessage/dist/index.js.PostmsgTransport.send @ index.js:43
handler @ index.js:46
push../node_modules/@storybook/channels/dist/index.js.Channel.emit @ index.js:55
action @ action.js:32
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:270
executeDispatch @ react-dom.development.js:561
executeDispatchesInOrder @ react-dom.development.js:583
executeDispatchesAndRelease @ react-dom.development.js:680
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:688
forEachAccumulated @ react-dom.development.js:662
runEventsInBatch @ react-dom.development.js:816
runExtractedEventsInBatch @ react-dom.development.js:824
handleTopLevel @ react-dom.development.js:4826
batchedUpdates$1 @ react-dom.development.js:20439
batchedUpdates @ react-dom.development.js:2151
dispatchEvent @ react-dom.development.js:4905
(anonymous) @ react-dom.development.js:20490
unstable_runWithPriority @ scheduler.development.js:255
interactiveUpdates$1 @ react-dom.development.js:20489
interactiveUpdates @ react-dom.development.js:2170
dispatchInteractiveEvent @ react-dom.development.js:4882
My code is as simple as
<Button onClick={actions('clicked')}Default</Button>
Button component accepts the onClick and prop and sets on <input type="button" onClick={props.onClick} />
.
Versions are following:-
"@storybook/addon-actions": "5.0.11",
"@storybook/addon-links": "5.0.11",
"@storybook/addons": "5.0.11",
"@storybook/react": "5.0.11",
i just wanted to pass this on. we have been having this issue for a while now (in JS, storybook-react)
we fixed it with a small tweak to how we called actions. it seemed to be an issue of how the addon was serializing the date. maybe this just applies to us, but also maybe it'll help some folk
fixed.
I'm also having this issue with the errors / warnings about reusing synthetic events. Any ideas to do a quick fix? There must be a way to wrap action
so that we call event.persist() before it runs?
I'm having the same issue. Any workaround will be greatly appreciated.
@montezume It worked for me after removing import babel-polyfill.
@montezume Thats what this code does.
import { action as brokenAction } from "@storybook/addon-actions"
const action: typeof brokenAction = (name, options) => {
const constructedAction = brokenAction(name, options)
return event => constructedAction(event.persist())
}
<Button onPress={action("Button pressed")} />
Not sure if there are any serious implications to calling persist on all of these events.
Edit: Actually this dismisses the warning but doesn't seem to pass the event to storybook.
Edit2: So I think I was using persist incorrectly. It doesn't return the event object, so needs to be persisted and then the original event object passed through. This fails due to a circular reference in the javascript. Have spent too long on this now so am going to give up but the best i'v managed is to get is an event logged in storybook with no details.
Ermahgerd!! I just released https://github.com/storybookjs/storybook/releases/tag/v5.3.0-alpha.39 containing PR #8690 that references this issue. Upgrade today to try it out!
You can find this prerelease on the @next
NPM tag.
Closing this issue. Please re-open if you think there's still more to do.
This shouldn't be closed. The PR explicitly states
"The issue #6471 still persists, but at least we can avoid it by not passing react events to it directy by doing."
You might consider modifying your release script to require the use of specific keywords to auto-close issues, like GitHub's native functionality.
This is my solution to action logging concerning React synthetic events.
The key is to set view
to undefined, because it's a reference to window
, and logging window substantially slows down the performance of storybook (because window is giant-- that's by no means Storybook's fault or anything).
Use this facade for Storybook's action
function throughout your project:
import { action } from '@storybook/addon-actions';
/* Partial event logging, as full logging can be expensive/slow
* Invocation: partialLog('actionName')(eventObj, ...args)
*/
export const partialAction = (actionName) => {
const beacon = action(actionName);
return (eventObj, ...args) => {
beacon({ ...eventObj, view: undefined }, ...args);
};
};
Literal example in a story:
const Template: Story<AccordionProps> = (args) => <Accordion {...args} />;
export const Simple = Template.bind({});
Simple.args = {
header: 'Hello World',
body: 'This is my example accordion.',
onChange: partialAction('onChange'), // fires whenever my accordion expands or collapses
};
This fix gets rid of React error message:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the method `isDefaultPrevented` on a released/nullified synthetic event. This is a no-op function. If you must keep the original synthetic event around, use event.persist(). See https://fb.me/react-event-pooling for more information.
It's a good compromise of logging nearly all the data (except the 'view' property), and keeping Storybook fast.
Most helpful comment
This is my solution to action logging concerning React synthetic events.
The key is to set
view
to undefined, because it's a reference towindow
, and logging window substantially slows down the performance of storybook (because window is giant-- that's by no means Storybook's fault or anything).Use this facade for Storybook's
action
function throughout your project:Literal example in a story:
This fix gets rid of React error message:
It's a good compromise of logging nearly all the data (except the 'view' property), and keeping Storybook fast.