React + ES6 Babel spits the following error message whenever I try to access undefined (ex. trying person.age where person === undefined.)
This also happens when I mistype an import statement or make a mistake when I destructure a props object. For example, I could make the following mistake:
const { name, age } = this.props.person
// but `this.props.person` only has a `name` property.
Such lack of error messages is a pain. Is there some option that I missed to set? How is everyone coping with this problem?
It is a highly requested feature and probably is going to be implemented in next React version. For now you can use redbox-react. As far as I know react-transform-catch-errors is deprecated.
/* global __DEV__ */
import React from 'react'
import { render } from 'react-dom'
import App from './components/App'
const root = document.getElementById('root')
if (__DEV__) {
const RedBox = require('redbox-react').default
try {
render(<App />, root)
} catch (e) {
render(<RedBox error={e} />, root)
}
} else {
render(<App />, root)
}
Yes, this is annoying. One way that helps, is to wrap the render-method of every React-component with try / catch, so you can see the actual error and not the gibberish provided by React. Add this to your babel.js-config, so it's automatically done: https://github.com/gaearon/react-transform-catch-errors.
Related
Recently new react-router 6.4 was released and it has the ability to load data before render of component. (https://reactrouter.com/en/main/start/overview#data-loading)
This seems like a cool feature. And I want to use it with RTK Query, since I already use Redux Toolkit.
So I want to to a basic thing, I have the api to load posts. I want to load them, and if request fails - redirect to other page. In react-router 6.4 it all can be done in router(https://reactrouter.com/en/main/start/overview#redirects).
Router is outside of scope of react, so I can not use hooks which are provided by rtk query, so it means that I have to use rtk query without hooks, which according to documentation is totally possible (https://redux-toolkit.js.org/rtk-query/usage/usage-without-react-hooks)
So my problem is, how do I read status of the request IN the react-router loader. I am able to read status in components, using hooks, but it makes components "dirty" and spreads the logic across the app.
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { Provider } from "react-redux";
import { store } from "./redux/redux";
import { Comments } from "./Comments";
import { Posts } from "./Posts";
import { Root } from "./Root";
import { postsApi } from "./redux/redux";
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
},
{
path: "posts",
element: <Posts />,
loader: () => {
store.dispatch(postsApi.endpoints.getPosts.initiate());
const request = postsApi.endpoints.getPosts.select()(store);
console.log(request);
return request;
},
},
{
path: "/comments",
element: <Comments />,
},
]);
const root = ReactDOM.createRoot(
document.getElementById("root") as HTMLElement
);
root.render(
<Provider store={store}>
<RouterProvider router={router} />
</Provider>
);
I am trying to use example from the docs, but I always get status "uninitialized" in the console, like the request had never been made, but it was, I can see the data in redux dev tools. And I also get the error "No data found at state.postsApi. Did you forget to add the reducer to the store?"
You are on the right track here, but you need to call unwrap() on the promise returned by dispatch, which will either return the result if successful or throw if not. I've modified your snippet to show what I mean.
loader: () => {
const p = store.dispatch(postsApi.endpoints.getPosts.initiate());
try {
const response = await p.unwrap()
return response
} catch (e) {
// see https://reactrouter.com/en/main/fetch/redirect
return redirect("/login")
} finally {
p.unsubscribe()
}
},
You would probably do something along the lines
const promise = dispatch(api.endpoints.myEndpoint.initiate(someArgument))
await promise // wait for data to be there
promise.unsubscribe() // remove the subscription. The data will stay in cache for 60 seconds and the component can subscribe to it in that timeframe.
Note that I do not access the data here and you probably shouldn't.
While it will be available after that await promise, I would use the loader only for data to be present - and then use the normal useMyEndpointQuery(someArgument) in the component to access that data.
You need to use the hook so the cache knows that your component is actually using that data - otherwise it would be removed from the cache after 60 seconds (or if you never unsubscribed, it would never be removed).
At that point there is no real benefit of passing that data from the loader function into the component - it will already be able to access it through the hook anyways.
So my suggestion: initiate and await the fetch from the loader, but actually access the data as before from the component.
I have a project which is on react but files are not .js instead they are .tsx and I am trying to use stripe library but keep getting error.
I have tried few different libraries which help setting up stripe but I am keep getting stuck on this errr.
Please help or direct me to correct library which help me setup stripe.
my codes are
import ReactDOM from "react-dom";
import StripeCheckout from 'react-stripe-checkout';
import axios from "axios";
function handleToken(token, addresses) {
console.log(token, addresses);
}
export default function Webinar() {
return (
<div className="container">
<StripeCheckout stripeKey = "mykey"
token={handleToken}
name="Tesla Roadster"
billingAddress
shippingAddress
/>
</div>
);
}
The problem is saying that your Typescript repo is now strict mode enabled which forces you specify the typing. If you wish to keep it silent, you can simply switch it to false in tsconfig.json:
{
"compilerOptions": {
"strict": false,
// ...
}
}
Change your function handleToken to be a variable with has the same type of your component prop as following:
const handleToken: StripeCheckout['props']['token'] = (token) => {
// You can receive hint from token type here
}
On my own code I tried to use react-router's useHistory by adding it to the imports:
import {BrowserRouter as Router, Link, Route, Switch, useHistory} from "react-router-dom";
and then defining a variable with it on my App() function:
let history = useHistory();
When I do that, I get the error:
TypeError: useContext(...) is undefined
coming from react-router's hooks.js, the specific line is:
return useContext(Context).history;
The whole file looks like this:
import React from "react";
import invariant from "tiny-invariant";
import Context from "./RouterContext.js";
import matchPath from "./matchPath.js";
const useContext = React.useContext;
export function useHistory() {
if (__DEV__) {
invariant(
typeof useContext === "function",
"You must use React >= 16.8 in order to use useHistory()"
);
}
return useContext(Context).history;
}
export function useLocation() {
if (__DEV__) {
invariant(
typeof useContext === "function",
"You must use React >= 16.8 in order to use useLocation()"
);
}
return useContext(Context).location;
}
export function useParams() {
if (__DEV__) {
invariant(
typeof useContext === "function",
"You must use React >= 16.8 in order to use useParams()"
);
}
const match = useContext(Context).match;
return match ? match.params : {};
}
export function useRouteMatch(path) {
if (__DEV__) {
invariant(
typeof useContext === "function",
"You must use React >= 16.8 in order to use useRouteMatch()"
);
}
return path
? matchPath(useLocation().pathname, path)
: useContext(Context).match;
}
Some more context:
I tried accessing React.useContext on my own code and it is defined and it is a function.
Any ideas what might be going on here?
I think that you should wrap your App in index.js with the BrowserRouter (as Router) and then in your App you define the Switch and Routes. Because you cannot use useHistory or useLocation in the same file where you use BrowserRouter.
So, use BrowserRouter wrapper one level up.
That happens because you need to wrap your component in a Router element. e.g:
import React from 'react';
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
// import MyComponent
const history = createBrowserHistory();
const MyApp = ()=> (
<Router {...{ history }}>
<MyComponent />
</Router>
);
export default MyApp;
It's definately not the case for this specific issue, but maybe someone will end up with a similar issue as I did.
For me the solution was to import hooks from react-router-dom instead of react-router package.
In my case I was trying to implement custom hook in another local package and it turned out that package didn't have react-router nor react-router-dom as dependency.
Error message was exactly the same and no other error from IDE or compiler.
Took me quite a while to figure this out. So the bottom line is: double-check your dependencies.
I've run into a similar issue with useRouteMatch(). I'm not sure if the cause is the same. I receive the error Cannot read property 'match' of undefined from line useContext(Context).match; when calling useRouteMatch() in my tests.
Option 1:
One of the ways the return from useContext can be undefined is if the Context supplied to useContext doesn't include any data. For example if you remove value={{ name: "Pupeno" }} from https://codesandbox.io/s/react-hooks-usecontext-example-wv76d?file=/src/index.js:320-347 you'll see a similar error.
There could be a similar bug in react-router-dom that allows the Context to be empty when it's called from these hooks.
Option 2:
It's hard to tell without looking at your code. It could also be something like https://github.com/ReactTraining/react-router/issues/7332
I get this warring in my react app.
It says componentWillReceiveProps has been renamed...
But I don't have "componentWillReceiveProps" in my code only effects ...
Maybe it is inside in node modules.
So i trying to ignore them
But i don't know how...
I used create-react-app
And i am using ts-lint.
Largely inspired from this answer
const error = console.error;
function logError(...parameters) {
let filter = parameters.find(parameter => {
return (
// Filter error because XXX
parameter.includes("Warning: %s is deprecated in StrictMode")
// Another error to filter because of YYYY
|| parameter.includes("Warning:")
);
});
if(!filter) error(...parameters);
}
console.error = logError;
Note that this code only works for errors, but you can duplicate it for console.warn or info
You can manage this in a particular .js file, and import it in the App.js
By using below code you can hide the desirable warnings
import React from 'react';
import { YellowBox } from 'react-native';
import AppNavigator from './app/main';
YellowBox.ignoreWarnings([
'Warning: isMounted(...) is deprecated',
'Module RCTImageLoader',
'Class RCTCxxModule',
'Task orphaned for request ',
'Warning',
'Require',
'Missing field __typename in',
'Node',
]);
const App = () => <AppNavigator />;
export default App;
After wrapping a React Component with the appropriate provider, the store is still not found within the jest testing environment. Is there something that I am missing, or another cleaner way to go about this?
This is the practice that is functional for other stores, and I have used with other components, so I don't see a reason why this shouldn't work. The renderer should be creating an object wrapped with the TextContext that it needs to read from in order to populate fields.
Context
import { connect } from 'react-redux';
import React, { createContext } from 'react';
export const TextContext = createContext({});
export function TextProvider({ children, text }) {
return <TextContext.Provider value={text}>{children}</TextContext.Provider>;
}
export const TextConsumer = TextContext.Consumer;
function renderComposition(props) {
const text = {
... // some text objects
};
return (
<TextProvider text={text}>
<Composition {...props} />
</TextProvider>
);
}
target failing line
beforeEach(() => {
...
subject = mount(renderer.create(renderComposition(props)));
...
)};
with error of
Invariant Violation: Could not find "store" in either the context or props of "Connect(Composition)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(Composition)".
I guess your component requires mocked store, you can provide it by creating mockReduxState.js
import configureMockStore from "redux-mock-store";
export const createMockStore = state => configureMockStore()(state);
Updating the failing test by passing mockedStore.
beforeEach(() => {
...
let updatedProp = {...props, store:createMockStore};
subject = mount(renderer.create(renderComposition(updatedProp)));
...
)};
Turns out the issue was unrelated, I was importing the component rather than the connected container, so the store was never getting set. Names are half of the battle turns out. The mocking the store option is also a great way to handle this 👍 thanks paragxvii