I having been trying to update the data using UseState with Typescript. The data is never updated what so ever. I am not sure what is it that I am missing. I just want to make sure that the information from local mock data that accepts those 5 properties and be send or updated to the store data. But whenever the button is pressed I am still get the same information that's already there and the mock data was never imported in. Help me if there's something I am missing or something I may need to change. Thank you, and let me know if you need any more informations.
import verification from '../mock-api/sample/TripVerificationSample.json';
interface VerificationTripProps {
isVisible: boolean;
style?: {};
onModalBack: () => void;
onPress: () => void;
data?: Reservation[];
}
const TripVerificationModal: React.FC<VerificationTripProps> = ({
isVisible = false,
onModalBack,
onPress,
data,
}) => {
console.log('before data is pushed ' + JSON.stringify(data));
const [updateData, setUpdateData] = useState<Reservation[]>([]);
const LoadConfirmInfo = () => {
//set old array to add new array
setUpdateData(previous => [
...previous,
{
confirmNumber: verification.confirmNumber,
startDate: new Date(verification.startDate),
endDate: new Date(verification.endDate),
hotel: verification.hotel,
status: ReservationStatusType.Upcoming,
},
]);
console.log('checking if info is pushed ' + JSON.stringify(updateData));
};
return (
<View>
<BackBaseModal
isVisible={isVisible}
onModalBack={onModalBack}
modalText={tripVerification.headerText}
subText={tripVerification.subText}
buttonText={tripVerification.confirmBtn}
onPress={() => {
onPress();
LoadConfirmInfo();
}}>
</View>
It is not guaranteed that the state is directly updated since setState is an async function! By directly logging the state after setting it, will most likely log the old value.
However, setting a new state causes a rerender, thus it is guaranteed that the new value is available in the next render cycle. This can be validated by using a useEffect with the states value as a dependency.
useEffect(() => {
console.log(updateData)}
, [updateData])
Related
I am creating a React App which will be used to display Dynamic Maps for DnD (vid files). Based on the User Input in a select field, a video player will get the specific video file from the firebase firestore, where I store the video files.
const Streamplayer = ({vidSelection}) => { //vidSelection is the event.target.value from the Select Input Field (basically a String)
const [links, setLinks] = useState([])
console.log(vidSelection);
useEffect(() => {
getLinks()
}, [])
useEffect(() => {
console.log(links)
}, [links])
function getLinks(){
const vidRef = collection(db, 'links');
getDocs(vidRef).then(response => {
console.log(response.docs)
const lnks = response.docs.map(doc => ({
data: doc.data(),
id: doc.id,
}))
setLinks(lnks)
}).catch(error => console.log(error.message));
}
function getVid(){
const toReturn = links.map((link) => link.data.vidSelection);//I want to change whatever gets returned based on input
console.log(toReturn)
return toReturn;
}
return (
<video
controls={false}
autoPlay
muted
loop
className="Video"
key={getVid()}
>
<source src={getVid()} type="video/mp4" />
</video>
)
}
export default Streamplayer
So in the method getVid() I request the data stored in the Firebase Firestore "Links" Collection and I want to change whichever I get based on the userInput. So if the User chooses the map "Grotto", I want to make the call "link.data.grotto". But since vidSelection is a String, I can't simply insert it in this call. Any Ideas how to solve this?
You can make useEffect get re-called when props change, by providing the prop in the dependency list for useEffect. Simply change your first useEffect call to:
useEffect(() => {
getLinks()
}, [vidSelection])
When the selection changes, useEffect will fire and call getLinks, which will update your state.
(Also, minor suggestion: remove the getVid() function, and just set a const videoSource = links.map((link) => link.data.vidSelection) in the function body. Right now you're calling the function twice which will cause the mapping to happen twice, and I think it's generally clearer to have consts flow directly from state, makes it easier to reason about state.)
I have a question about the "proper" (or most idiomatic) way to implement network fetch behavior in React based on a single changing property.
A simplified example of the functionality I'm building is below: I am looking to build a multi-page form that "auto-saves" a draft of form inputs as the user navigates back/forth between pages.
TL;DR - I thought useEffect hooks would be the right way to save a draft to the backend every time a url slug prop changes, but I'm running into issues, and wondering about suggestions for the "right" tool for this type of behavior.
Here is my attempt so far. My code is technically working how I want it to, but violates React's recommended hook dependency pattern (and breaks the exhaustive-deps ESLint rule).
import React from 'react';
const ALL_SLUGS = [
'apple',
'banana',
'coconut',
];
function randomUrlSlug() {
return ALL_SLUGS[Math.floor((Math.random() * ALL_SLUGS.length))];
}
// just resovles the same object passed in
const dummySaveDraftToBackend = (input) => {
return new Promise((resolve, _reject) => {
setTimeout(() => {
resolve(input);
}, 1000);
});
};
export function App() {
const [urlSlug, setUrlSlug] = React.useState(randomUrlSlug());
return (
<MyComponent urlSlug={urlSlug} setUrlSlug={setUrlSlug} />
);
}
export function MyComponent({ urlSlug, setUrlSlug }) {
const [loading, setLoading] = React.useState(false);
const [complexState, setComplexState] = React.useState({ foo: 'bar', baz: 'wow', responseCount: 0 });
// useCallback memoization is technically unnecessary as written here,
// but if i follow the linter's advice (listing handleSave as a dependency of the useEffect below), it also suggests memoizing here.
// However, complexState is also technically a dependency of this callback memo, which causes the fetch to trigger every time state changes.
//
// Similarly, moving all of this inside the effect hook, makes the hook dependent on `complexState`, which means the call to the backend happens every time a user changes input data.
const handleSave = React.useCallback(() => {
console.log('*** : start fetch');
setLoading(true);
dummySaveDraftToBackend(complexState).then((resp) => {
console.log('fetch response: ', resp);
// to keep this example simple, here we are just updating
// a dummy "responseCount", but in the actual implementation,
// I'm using a state reducer, and want to make some updates to form state based on error handling, backend validation, etc.
setComplexState((s) => ({
...resp,
responseCount: s.responseCount + 1,
}));
setLoading(false);
});
}, [complexState]);
// I know this triggers on mount and am aware of strategies to prevent that.
// Just leaving that behavior as-is for the simplified example.
React.useEffect(() => {
if (urlSlug) {
handleSave();
}
}, [urlSlug]); // <- React wants me to also include my memoized handleSave function here, whose reference changes every time state changes. If I include it, the fetch fires every time state changes.
return (
<div className="App">
<h2>the current slug is:</h2>
<h3>{urlSlug}</h3>
<div>the current state is:</div>
<pre>{JSON.stringify(complexState, null, 2)}</pre>
<div>
<h2>edit foo</h2>
<input value={complexState.foo} onChange={(e) => setComplexState((s) => ({ ...s, foo: e.target.value }))} disabled={loading} />
</div>
<div>
<h2>edit baz</h2>
<input value={complexState.baz} onChange={(e) => setComplexState((s) => ({ ...s, baz: e.target.value }))} disabled={loading} />
</div>
<div>
<button
type="button"
onClick={() => setUrlSlug(randomUrlSlug())}
disabled={loading}
>
click to change to a random URL slug
</button>
</div>
</div>
);
}
As written, this does what I want it to do, but I had to omit my handleSave function as a dependency of my useEffect to get it to work. If I list handleSave as a dependency, the hook then relies on complexState, which changes (and thus fires the effect) every time the user modifies input.
I'm concerned about violating React's guidance for not including dependencies. As-is, I would also need to manually prevent the effect from running on mount. But because of the warning, I'm wondering if I should not use a useEffect pattern for this, and if there's a better way.
I believe I could also manually read/write state to a ref to accomplish this, but haven't explored that in much depth yet. I have also explored using event listeners on browser popstate events, which is leading me down another rabbit hole of bugginess.
I know that useEffect hooks are typically intended to be used for side effects based on event behavior (e.g. trigger a fetch on a button click). In my use case however, I can't rely solely on user interactions with elements on the page, since I also want to trigger autosave behavior when the user navigates with their browser back/forward controls (I'm using react-router; current version of react-router has hooks for this behavior, but I'm unfortunately locked in to an old version for the project I'm working on).
Through this process, I realized my understanding might be a bit off on proper usage of hook dependencies, and would love some clarity on what the pitfalls of this current implementation could be. Specifically:
In my snippet above, could somebody clarify to me why ignoring the ESLint rule could be "bad"? Specifically, why might ignoring a dependency on some complex state can be problematic, especially since I dont want to trigger an effect when that state changes?
Is there a better pattern I could use here - instead of relying on a useEffect hook - that is more idiomatic? I basically want to implement a subscriber pattern, i.e. "do something every time a prop changes, and ONLY when that prop changes"
If all the "state" that is updated after saving it to backend is only a call count, declare this as a separate chunk of state. This eliminates creating a render loop on complexState.
Use a React ref to cache the current state value and reference the ref in the useEffect callback. This is to separate the concerns of updating the local form state from the action of saving it in the backend on a different schedule.
Ideally each useState hook's "state" should be closely related properties/values. The complexState appears to be your form data that is being saved in the backend while the responseCount is completely unrelated to the actual form data, but rather it is related to how many times the data has been synchronized.
Example:
export function MyComponent({ urlSlug, setUrlSlug }) {
const [loading, setLoading] = React.useState(false);
const [complexState, setComplexState] = React.useState({ foo: 'bar', baz: 'wow' });
const [responseCount, setResponseCount] = React.useState(0);
const complexStateRef = React.useRef();
React.useEffect(() => {
complexStateRef.current = complexState;
}, [complexState]);
React.useEffect(() => {
const handleSave = async (complexState) => {
console.log('*** : start fetch');
setLoading(true);
try {
const resp = await dummySaveDraftToBackend(complexState);
console.log('fetch response: ', resp);
setResponseCount(count => count + 1);
} catch(error) {
// handle any rejected Promises, errors, etc...
} finally {
setLoading(false);
}
};
if (urlSlug) {
handleSave(complexStateRef.current);
}
}, [urlSlug]);
return (
...
);
}
This feels like a move in the wrong direction (towards more complexity), but introducing an additional state to determine if the urlSlug has changed seems to work.
export function MyComponent({ urlSlug, setUrlSlug }) {
const [slug, setSlug] = React.useState(urlSlug);
const [loading, setLoading] = React.useState(false);
const [complexState, setComplexState] = React.useState({ foo: 'bar', baz: 'wow', responseCount: 0 });
const handleSave = React.useCallback(() => {
if (urlSlug === slug) return // only when slug changes and not on mount
console.log('*** : start fetch');
setLoading(true);
dummyFetch(complexState).then((resp) => {
console.log('fetch response: ', resp);
setComplexState((s) => ({
...resp,
responseCount: s.responseCount + 1,
}));
setLoading(false);
});
}, [complexState, urlSlug, slug]);
React.useEffect(() => {
if (urlSlug) {
handleSave();
setSlug(urlSlug)
}
}, [urlSlug, handleSave]);
Or move handleSave inside the useEffect (with additional slug check)
Updated with better semantics
export function MyComponent({ urlSlug, setUrlSlug }) {
const [autoSave, setAutoSave] = React.useState(false); // false for not on mount
React.useEffect(() => {
setAutoSave(true)
}, [urlSlug])
const [loading, setLoading] = React.useState(false);
const [complexState, setComplexState] = React.useState({ foo: 'bar', baz: 'wow', responseCount: 0 });
React.useEffect(() => {
const handleSave = () => {
if(!autoSave) return
console.log('*** : start fetch');
setLoading(true);
dummyFetch(complexState).then((resp) => {
console.log('fetch response: ', resp);
setComplexState((s) => ({
...resp,
responseCount: s.responseCount + 1,
}));
setLoading(false);
});
}
if (urlSlug) {
handleSave();
setAutoSave(false)
}
}, [autoSave, complexState]);
I am learning react, and given this simple example of using SWR to fetch some items from an API and showing the items with groups using fluentui DetailedList - I am running into a problem with the groups.
Whenever I click a group in UI to collapse/uncollapse, that seems to trigger a rerender, and then the component will createGroups(data) again which resets the UI again back to original state as the groups object is recalculated.
Where am I supposed to actually store / calculate the groups information of my data? Initial it needs to be created, but from there it seems that it should only needs to be reevaluated whenvere the swr api returns new data - and then i still properly would want to merge in the current state from collapsed groups that the user might have changed in the UI.
Is it because i properly should not use SWR as it refreshes data live - and only do it on page refresh?
const SWR = ({ children, listid, onSuccess }: { children: ((args: SWRResponse<any, any>) => any), listid: string, onSuccess?: any }) => {
const url = `http://localhost:7071/api/Lists/${listid}`;
console.log(url);
const {data,error } = useSWR(url, { fetcher: fetcher, isPaused: () => listid === undefined, onSuccess });
const items = data.value;
const groups = createGroups(data)
return <... DetailsList group={groups} items={items} ... >; // ... left out a few details ...
};
What about adding a state for holding the groups and an useEffect for when data changes and insde the useEffect you should check if the content has changed before updating the groupState.
const hasChanged(data) => {
return data.notEquals(state.data)); // write your own logic for comparing the result
};
useEffect(() => { if (hasChanged(data)) {
setState(prev=> ({ ...prev, group: createGroup(data), data: data });
}}, [data]);
You dont actually need to store the group, you can just hold the data in your state, but the important part is to be able to check if any change actually took place before changing the state.
Another thing worth trying is the compare option in the useSWR hook. So instead of placing the "hasChanged" logic inside an useEffect hook, perhaps it could be in the compare function. Haven't had the chanse to test this myself though.
A third and final option would be to place the creation of groups inside your fetcher. Perhaps the most intuitive solution for this particular case, though I'm not completely sure it will prevent the unnecessary re-renders.
const fetcher = url => axios.get(url).then(res=> {
return {
items: res.data.value,
groups: createGroups(res.data),
};
});
const SWR = ({ children, listid, onSuccess }: { children: ((args: SWRResponse<any, any>) => any), listid: string, onSuccess?: any }) => {
const { data, error } = useSWR(url, fetcher, ...);
return <... DetailsList group={data.groups} items={data.items} ... >; // ... left out a few details ...
};
I'd like to "fire an event" in one component, and let other components "subscribe" to that event and do some work in React.
For example, here is a typical React project.
I have a model, fetch data from server and several components are rendered with that data.
interface Model {
id: number;
value: number;
}
const [data, setData] = useState<Model[]>([]);
useEffect(() => {
fetchDataFromServer().then((resp) => setData(resp.data));
}, []);
<Root>
<TopTab>
<Text>Model with large value count: {data.filter(m => m.value > 5).length}</Text>
</TobTab>
<Content>
<View>
{data.map(itemData: model, index: number) => (
<Item key={itemData.id} itemData={itemData} />
)}
</View>
</Content>
<BottomTab data={data} />
</Root>
In one child component, a model can be edited and saved.
const [editItem, setEditItem] = useState<Model|null>(null);
<Root>
<TopTab>
<Text>Model with large value count: {data.filter(m => m.value > 5).length}</Text>
</TobTab>
<ListScreen>
{data.map(itemData: model, index: number) => (
<Item
key={itemData.id}
itemData={itemData}
onClick={() => setEditItem(itemData)}
/>
)}
</ListScreen>
{!!editItem && (
<EditScreen itemData={editItem} />
)}
<BottomTab data={data} />
</Root>
Let's assume it's EditScreen:
const [model, setModel] = useState(props.itemData);
<Input
value={model.value}
onChange={(value) => setModel({...model, Number(value)})}
/>
<Button
onClick={() => {
callSaveApi(model).then((resp) => {
setModel(resp.data);
// let other components know that this model is updated
})
}}
/>
App must let TopTab, BottomTab and ListScreen component to update data
without calling API from server again (because EditScreen.updateData already fetched updated data from server) and
not passing updateData function as props (because in most real cases, components structure is too complex to pass all functions as props)
In order to solve above problem effectively, I'd like to fire an event (e.g. "model-update") with an argument (changed model) and let other components subscribe to that event and change their data, e.g.:
// in EditScreen
updateData().then(resp => {
const newModel = resp.data;
setModel(newModel);
Event.emit("model-updated", newModel);
});
// in any other components
useEffect(() => {
// subscribe model change event
Event.on("model-updated", (newModel) => {
doSomething(newModel);
});
// unsubscribe events on destroy
return () => {
Event.off("model-updated");
}
}, []);
// in another component
useEffect(() => {
// subscribe model change event
Event.on("model-updated", (newModel) => {
doSomethingDifferent(newModel);
});
// unsubscribe events on destroy
return () => {
Event.off("model-updated");
}
}, []);
Is it possible using React hooks?
How to implement event-driven approach in React hooks?
There cannot be an alternative of event emitter because React hooks and use context is dependent on dom tree depth and have limited scope.
Is using EventEmitter with React (or React Native) considered to be a good practice?
A: Yes it is a good to approach when there is component deep in dom tree
I'm seeking event-driven approach in React. I'm happy with my solution now but can I achieve the same thing with React hooks?
A: If you are referring to component state, then hooks will not help you share it between components. Component state is local to the component. If your state lives in context, then useContext hook would be helpful.
For useContext we have to implement full context API with MyContext.Provider and MyContext.Consumer and have to wrap inside high order (HOC) component
Ref
so event emitter is best.
In react native, you can use react-native-event-listeners package
yarn add react-native-event-listeners
SENDER COMPONENT
import { EventRegister } from 'react-native-event-listeners'
const Sender = (props) => (
<TouchableHighlight
onPress={() => {
EventRegister.emit('myCustomEvent', 'it works!!!')
})
><Text>Send Event</Text></TouchableHighlight>
)
RECEIVER COMPONENT
class Receiver extends PureComponent {
constructor(props) {
super(props)
this.state = {
data: 'no data',
}
}
componentWillMount() {
this.listener = EventRegister.addEventListener('myCustomEvent', (data) => {
this.setState({
data,
})
})
}
componentWillUnmount() {
EventRegister.removeEventListener(this.listener)
}
render() {
return <Text>{this.state.data}</Text>
}
}
Not sure why the EventEmitter has been downvoted, but here's my take:
When it comes to state management, I believe using a Flux-based approach is usually the way to go (Context/Redux and friends are all great). That said, I really don't see why an event-based approach would pose any problem - JS is event based and React is just a library after all, not even a framework, and I can't see why we would be forced to stay within its guidelines.
If your UI needs to know about the general state of your app and react to it, use reducers, update your store, then use Context/Redux/Flux/whatever - if you simply need to react to specific events, use an EventEmitter.
Using an EventEmitter will allow you to communicate between React and other libraries, e.g. a canvas (if you're not using React Three Fiber, I dare you to try and talk with ThreeJS/WebGL without events) without all the boilerplate. There are many cases where using Context is a nightmare, and we shouldn't feel restricted by React's API.
If it works for you, and it's scalable, just do it.
EDIT: here's an example using eventemitter3:
./emitter.ts
import EventEmitter from 'eventemitter3';
const eventEmitter = new EventEmitter();
const Emitter = {
on: (event, fn) => eventEmitter.on(event, fn),
once: (event, fn) => eventEmitter.once(event, fn),
off: (event, fn) => eventEmitter.off(event, fn),
emit: (event, payload) => eventEmitter.emit(event, payload)
}
Object.freeze(Emitter);
export default Emitter;
./some-component.ts
import Emitter from '.emitter';
export const SomeComponent = () => {
useEffect(() => {
// you can also use `.once()` to only trigger it ... once
Emitter.on('SOME_EVENT', () => do what you want here)
return () => {
Emitter.off('SOME_EVENT')
}
})
}
From there you trigger events wherever you want, subscribe to them, and act on it, pass some data around, do whatever you want really.
We had a similar problem and took inspiration from useSWR.
Here is a simplified version of what we implemented:
const events = [];
const callbacks = {};
function useForceUpdate() {
const [, setState] = useState(null);
return useCallback(() => setState({}), []);
}
function useEvents() {
const forceUpdate = useForceUpdate();
const runCallbacks = (callbackList, data) => {
if (callbackList) {
callbackList.forEach(cb => cb(data));
forceUpdate();
}
}
const dispatch = (event, data) => {
events.push({ event, data, created: Date.now() });
runCallbacks(callbacks[event], data);
}
const on = (event, cb) => {
if (callbacks[event]) {
callbacks[event].push(cb);
} else {
callbacks[event] = [cb];
}
// Return a cleanup function to unbind event
return () => callbacks[event] = callbacks[event].filter(i => i !== cb);
}
return { dispatch, on, events };
}
In a component we do:
const { dispatch, on, events } = useEvents();
useEffect(() => on('MyEvent', (data) => { ...do something...}));
This works nicely for a few reasons:
Unlike the window Event system, event data can be any kind of object. This saves having to stringify payloads and what not. It also means there is no chance of collision with any built-in browser events
The global cache (idea borrowed from SWR) means we can just useEvents wherever needed without having to pass the event list & dispatch/subscribe functions down component trees, or mess around with react context.
It is trivial to save the events to local storage, or replay/rewind them
The one headache we have is the use of the forceUpdate every time an event is dispatched means every component receiving the event list is re-rendered, even if they are not subscribed to that particular event. This is an issue in complex views.
We are actively looking for solutions to this...
You can create use context in App.js using useContext, and then in you child component you can use values from it and update the context as soon as the context get updated it will update the values being used in other child component, no need to pass props.
You can achieve this with any React's global state management.
In your store, have a useEffect for your event subscription, and a reducer for each of your event.
If you have 2 data sources, the subscription and the query, then initialize your state values with your query, then listen to the subscription.
Something like this
const reducer = (state, action) => {
switch(action.type) {
case 'SUBSCRIBE':
return action.payload
default:
return state
}
}
Assuming you are using https://github.com/dai-shi/use-reducer-async
const asyncActions = {
QUERY: ({ dispatch }) => async(action) => {
const data = await fetch(...)
dispatch({ type: 'query', payload: data })
}
}
You can also use middleware in Redux
const [state, dispatch] = useReducer(reducer, initialValues, asyncActions)
useEffect(() => {
dispatch({ type: 'QUERY' })
Event.on((data) => {
dispatch({ type: 'SUBSCRIBE', payload: data })
})
return () => Event.off()
}, [])
return <Provider value={state}>{children}</Provider>
I am having this scenario, where I have a dropdown which pulls the accounts of a user and then based on its selection the content of the page changes. I am trying an approach which is shown below , It seems like setState does not get invoked properly or may be calling sequence may be wrong. Not really getting what is wrong. Changing drop down value does not update the content .
Help would be appreciated.
import * as React from 'react';
import Select from 'semantic-ui-react/dist/commonjs/addons/Select';
interface IState{
accountDetails[], // stores all details w.r.t an account
userAccounts: [], // stores all accounts w.r.t a user
selectedAccount : string, // selected account from the dropdown
[x: string] : any,
}
export default class App extends React.Component<{},IState> {
constructor(props:any){
super(props);
this.state = {
accountDetails: [],
userAccounts: [],
selectedAccount: ''
}
}
dropdownChange = (event: React.SyntheticEvent<HTMLElement>, data:any) => {
this.setState(prevState => ({
selectedAccount: data.value
}), () => {});
}
async componentDidMount()
{
await this.fetchUserAccounts();
}
fetchUserAccounts = async() => {
//fetch API call for getting all user accounts by passing a user ID
// I am able to get the data
fetch('/api/fetch/accounts'
.then(response => response.json())
.then(data => this.setState({ userAccounts: data}));
this.fetchAccountDetails();
}
fetchAccountDetails = async() =>
{
let URL = "/api/fetch/account?accountId=" +this.state.selectedAccount;
fetch('URL'
.then(response => response.json())
.then(data => this.setState({ accountDetails: data}));
}
render() {
return(
<div>
<Select
options={this.state.userAccounts}
name="selectedAccount"
value={this.state.selectedAccount}
onChange={this.dropdownChange}
/>
// component to display the details
<DetailComponent accounts={this.state.accountDetails} />
</div>
)
}
}
You need to call fetchAccountDetails right after changing the state, for the function to invoke using the latest state that the dropdown has changed:
dropdownChange = (event: React.SyntheticEvent<HTMLElement>, data:any) => {
this.setState(prevState => ({
selectedAccount: data.value
}), () => { this.fetchAccountDetails() });
}
the setState function is asynchronous, which means you need to take special precaution when updating state and expecting to use the updated value in the state synchronously. For this reason, the setState function has a second parameter which allows you to specify a callback which is executed when the state has actually been updated. This is where you would need to call the fetchAccountDetails function.
You can find the setState callback parameter described in the React docs here.
But you will have trouble compiling this either way. (a) Your interface should end each member declaration with a semicolon, not a comma. (b) You're missing a ")" on each line with a call to fetch. (c) In the fetchAccountDetails function you declare the URL variable, but then you pass a string 'URL' to the fetch function, not the variable.
Here is a working code sandbox showing the fix to your question, and the syntax fixes. I've commented out the calls to the fetch function since they will fail anyway.
https://codesandbox.io/s/thirsty-rain-2u69e