storybook-addons
storybook-addons copied to clipboard
Decorated component re-mounts on dispatch
Hello,
I'm trying to use the context addon for input-based components. For example:
import { useEffect } from 'react';
import { withReactContext } from 'storybook-react-context';
const InputWrapper = ({ value, children }) => (
<div>
<p>{value}</p>
{children}
</div>
);
export default {
component: InputWrapper,
title: 'InputWrapper',
};
export const Input = (args, { context: [ state, dispatch ] }) => {
const handleChange = (e) => {
const { target: { value } } = e;
dispatch({ value });
};
useEffect(() => {
console.info('mount');
return () => {
console.info('unmount');
}
}, [])
return (
<InputWrapper value={state.value}>
<input type="text" value={state.value} onChange={handleChange} />
</InputWrapper>
);
};
Input.decorators = [withReactContext({
initialState: {
value: 'Hello',
},
})];
Input.args = {};
I'm noticing that on every dispatch (input value change) story is re-mounted. Is there a way to avoid that, because on each keystroke input is re-mounted and focus is lost?
Thx
This is a fundamental laws of react thing. Context is essentially a prop that you don't have to pass. That means it is subject to the same rules as props... and when you change a component's props, the component re-renders.
I think this is actually a bug. I was able to get the focus to stay on the input by swapping out this decorator with my own simple one. The below decorator is working for me:
const withMyContext = (args) => (Story) => {
const [state, dispatch] = useReducer(filterReducer, args.initialState);
return (
<SearchContext.Provider value={[state, dispatch]}>
{Story()}
</SearchContext.Provider>
);
};
decorators: [
withMyContext({
Context: SearchContext,
initialState: {
...initialPredictiveState,
settings: {
search: {
suggestions: {
title: "Recommended search text",
},
},
},
},
}),
],