I am using this tutorial to install React for the front with an API built in Django.
https://sweetcode.io/how-use-djang-react-ap/
My repository for this projects so far is here:
https://github.com/AlexMercedCoder/DjangoReactCRM
When I npm run dev I get a syntax error in App.js, I've played with it and can't seem to figure it out. The error I get is.
ERROR in ./frontend/src/components/App.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError:
C:\Users\alexm\projects\DjangoReactCRM\drcrm\frontend\src
\components\App.js: Unexpected token, expected "," (29:6)
27 |
28 | wrapper ? ReactDOM.render(<app>, wrapper) : null;
> 29 | </app>
App.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
state = {
data: ''
};
componentDidMount() {
fetch("/api")
.then(response => {
return response.json();
})
.then(data => this.setState({ data: JSON.stringify(data)}));
}
render(){
return (
<p>Jason data = {this.state.data}</p>
)
}
}
wrapper ? ReactDOM.render(<app>, wrapper) : null;
</app>
First, the <app> component is closed outside the ternary operator, so you'd have to use <app></ app> or even simpler <app />.
wrapper ? ReactDOM.render(<app></app>, wrapper) : null;
or
wrapper ? ReactDOM.render(<app/>, wrapper) : null;
Then, all React components must start with a capital letter
to differentiate default DOM component from those created with React, so you have to use this notation.
wrapper ? ReactDOM.render(<App />, wrapper) : null;
Finally, I do not see the utility of the ternary operator at the end of your code. Normally, the second argument when we call reactDOM.render(X, Y) must represent the DOM element in which we will render our main React component (in this case, <App />).
By default, when we create a React project with create-react-app, we don't have to deal with these settings and the DOM element is automatically defined as <div id='root'></div> (check inside the <body> in public/index.html inside your project root).
So call document.getElementById('root') to get the DOM element and simply put the result as second argument.
ReactDOM.render(<App />, document.getElementById('root'));
If it persist, I suggest you to simply create another React project with create-react-app and copy/paste only the code you need.
To get more informations: Click here
I hope it can help you.
** I apologize if my explanations are not clear or if I made some mistakes.
There are three problems in your component.
I'm guessing wrapper was supposed to be document.getElementById("root") ? Even then the ternary condition doesn't make sense. It should be something like:
ReactDOM.render(
<App />,
document.getElementById("root")
)
You defined the component as App, yet in ReactDOM.render you are using app
You have </app> at the end of the file. It doesn't do anything in this case.
Related
I want to use http://tabulator.info/ with ember. I don't understand the documentation nor can I find any guides on configuration for ember. How can I start by creating a simple table?
Looking at the examples on the site, http://tabulator.info/, it seems that tabulator only needs an element to work (and some config).
So, our end goal is going to be to use a modifier with the ability to pass the tabulator config to it.
So, this is what we'll end up with:
<div {{tabulator someConfig}}></div>
Now, unfortunately, it looks like tabulator only accepts an id in its constructor. so we'll need to dynamically add that in to appears tabulator.
First thing you'll want to do is install https://github.com/ember-modifier/ember-modifier (be sure to read the docs as this is fun stuff)
Then, create a file in your app, app/modifiers/tabulator.js
and use these contents:
import Modifier from 'ember-modifier';
import Tabulator from 'tabulator';
import { guidFor } from '#ember/object/internals';
export default class TabulatorModifier extends Modifier {
id = guidFor(this);
get config() {
return this.args.positional[0];
}
didInstall() {
this.element.id = this.id;
let config = th
this.tabulator = new Tabulator(`#${this.id}`, this.config);
}
}
And then maybe in a component or controller or something, you'd have something like:
export default class MyComponent extends Component {
get myConfig() {
return { ... };
}
}
<div {{tabulator this.myConfig}}></div>
and that should be it.
You'll want to import the CSS in your app.css
So we are developing a Stenciljs component which wraps leaflet map and adds some additional functionality.
Now obviously we don't want or need to test Leaflet, but instead, just the parts in our wrapper components.
So, using the test examples, we create our tests,
import { LeMap } from "./le-map";
describe("Map component tests", () => {
it("Should build the map component", async () => {
const map = new LeMap();
expect(map).not.toBeNull();
});
});
try and load the components and test the public functions, but we get
TypeError: Cannot read property 'deviceXDPI' of undefined
> 1 | import {Component, Element, Listen, Method, Prop, Watch} from
'#stencil/core';
> 2 | import L from 'leaflet';
| ^
3 |
4 | #Component({
5 | shadow: false,
We believe this message is because the test is trying to render leaflet, and because it's not a true browser, it can't detect a view so throwing this error, so we've tried to mock leaflet in the tests, but still get the same problem.
We're tried to mock the leaflet module by using jest mocking
jest.genMockFromModule('leaflet');
but this made no diffrence
Only idea I've had is to separate the logic from the components, but that feels wrong, as we'd just be doing this for purpose of testing.
Versions in use are: leaflet: 1.3.4, #stencil: 0.15.2, jest: 23.4.2
Any other suggestions?
Further investigation with, thanks to #skyboyer 's suggestions, leads me to this line of the leaflet core browser.js file
leads me to this line of the leaflet core browser.js file
export var retina = (window.devicePixelRatio || (window.screen.deviceXDPI/window.screen.logicalXDPI)) > 1;
But I'm unable to mock the screen property of window as I get the following error
[ts] Cannot assign to 'screen' because it is a constant or a read-only property,
so I try the following.
const screen = {
deviceXDPI:0,
logicalXDPI:0
}
Object.defineProperty(window, 'screen', screen);
Object.defineProperty(window, 'devicePixelRatio', 0);
Same error, completely ignores this, so I try over riding the export.
jest.spyOn(L.Browser,'retina').mockImplementation(() => false);
No joy either, so tried
L.Browser.retina = jest.fn(() => false);
but get it tells me it's a constant and can't be changed (yet the implication stats var so ¯_(ツ)_/¯ )
Anything else I can try?
Further update,
I've managed to mock the window, but this sadly doesn't solve it.
const screenMock = {
deviceXDPI: 0,
logicalXDPI: 0
}
const windowMock = {
value: {
'devicePixelRatio': 0,
'screen': screenMock
}
}
Object.defineProperty(global, 'window', windowMock);
If I console log this, I get the right properties but as soon as I test the instantiation of the component it fails with
TypeError: Cannot read property 'deviceXDPI' of undefined
Reading around it seems Leaflet doesn't check for a DOM and just tries to render anyway, I can't see anyway around this, I saw a leaflet-headless package, but I don't know how I could swap them out just for testing.
Think I will need to look at another strategy for testing, probably protractor.
Found a solution, not fully tested yet, but the tests pass.
I did it by creating a
__mocks__
directory at the same level as the node_modules directory.
created a file called leaflet.js in it. It's a simple file it just contains.
'use strict';
const leaflet = jest.fn();
module.exports = leaflet;
then in my test file (le-map.spec.ts) I just added
jest.mock('leaflet')
before the imports
and now my test passes.
I tried doing this in the test itself but that just gave me the same error, it must be something in the loading sequence which means it has to be manually mocked beforehand.
Hope this helps others, it's been driving me mad for weeks.
I have a global property/variable with my app urls:
Vue.prototype.$apiUrls = {
root: 'http://localhost:8080/',
api: 'api/v1/'
// etc.
}
I use it inside my components as axios request:
axios.get(`${this.$apiUrls.root}${this.$apiUrls.api}/users/`)
Now I want to test my component's code, I've mocked axios already, but still I receive an error:
TypeError: Cannot read property '$apiUrls' of undefined
I've tried to define/mock this property inside each test and/or in JEST's setup file, like e.g.
global.$apiUrls = {...}
// or
Vue.prototype.$apiUrls = {...}
// or
Object.defineProperties(Vue.prototype, {$apiUrls: {...}})
I've also tried mocking it to window or this (yeah, thats silly), but with no success - I still receive that error - please help.
There is two ways to achieve this. One is using the Config option, as mentioned by #Aldarund. You can read about it here.
If you are using Jest, I recommend doing this in the jest.init.js file:
import { config } from '#vue/test-utils'
config.mocks['$apiUrls'] = {
'some/endpoint'
}
Then add this to the jest section of your package.json:
"setupFiles": [
"<rootDir>/jest.init.js"
]
Now it is globally mocked. If you want to do this on a per test basis, you can use the mocks mounting option:
const wrapper = shallowMount(Foo, {
mocks: {
$apiUrls: 'some/endpoint'
}
})
Hopefully this helps!
If you are interested I am compiling a collection of simple guides on how to test Vue components here. It's under development, but feel free to ask make an issue if you need help with other related things to testing Vue components.
I don't think the answers above work anymore (in 2020).
Here's what worked for me:
For vue-test-utils 1.x.x (Vue 2)
Create a new file, name it eg. jest.init.js
Give it the following content:
import { config } from "#vue/test-utils";
config.mocks["yourGlobalProperty"] = label => label; //you can replace it with your own mock
Add this to your jest.config.js (actually write "rootDir", don't replace anything with a real path)
module.exports = {
setupFiles: ["<rootDir>/jest.init.js"]
}
These files will be only ran before jest runs unit tests.
Note that I'm importing {config}, not the default export. I don't know why the default didn't work for me. Even the documentation for vue test utils doesn't import the default export anymore
Also make sure you're not trying to import from the old vue-test-utils package. (The new one is #vue/test-utils)
For #vue/test-utils 2.x.x (vue-test-utils-next) (Vue 3)
Follow steps like for 1.x.x above, but in step two, do this instead:
import { config } from "#vue/test-utils"; //2.0.0-beta.5
config.global.mocks = {
yourGlobalProperty: label => label
};
You can do it with vue-test-utils beta 15 and later.
Here docs
And some example would be:
import VueTestUtils from '#vue/test-utils'
VueTestUtils.config.mocks['$apiUrls'] = {
...
}
The question is simple and Im can't believe I cant found a solution (without context) for a situation as simple as this.
Im using react-intl.
I have an App.jsx with a child component Index.jsx with a SideBar.jsx with a CreateNewSomething.jsx.
In every components, the command
<FormattedMessage
id="new_object.fill_title"
defaultMessage='Please fill the "title" parameter'
/>
works perfectly thanks to <IntlProvider> provided by App.jsx
Unfortunally, I can't inject FormattedMessage as state value of a component.
Example:
<Input
s={6}
label={label_dash_title}
style={style_items_form}
onChange={this.onDashTitleChange}
onKeyPress={this.newDashHandleEnterKey}
error= { this.state.title_error }
/>
When the input field is not filled (is required) I want to print an error message.
Unfortunally I can't write:
const error_message = <FormattedMessage
id="new_dash.fill_title"
defaultMessage='Please fill the "title" parameter'
/>
this.setState({"title_error" : error_message});
because I get [object Object] and there is no property inside of it with my translated message.
Searching everywhere, I found I have to use this.props.intl.formatMessage({id: 'new_dash.fill_title'});
but this.props.intl is undefined.
I've tried, in App.jax, to include:
import {addLocaleData, IntlProvider, injectIntl, intlShape} from 'react-intl';
but it makes no difference.
I've tried to pass intl to every child component as props but intl is undefined in App.jsx too.
I don't know where is my mistake.
The module's Wiki explain the method but not how to use.
The solution is simple. You have to change the Export Syntax of your React Component and than this.props.intl will be magically available in the component:
export default injectIntl(MyComponent); //WORKS!!!
Unfortunally:
export default class injectIntl(MyComponent) extends React.Component //DOESN'T WORK
Is there a global loading flag available anywhere for react-apollo client? I have a “page wrapper” component that i’d like to apply ui effects to after all the child components have received their data.
I have set up apollo with redux so have ready access to the store (http://dev.apollodata.com/react/redux.html)
I could quite easily dispatch state changes from each component that receives data from apollo but I'd like this page wrapper component to not have any knowledge of its children nor their queries.
I have investigated using withApollo - http://dev.apollodata.com/react/higher-order-components.html#withApollo -
but don't see an api for a global is loading.
I've just released a library that solves this for Apollo 2: react-apollo-network-status.
The gist is:
import React, {Fragment} from 'react';
import ReactDOM from 'react-dom';
import {ApolloClient} from 'apollo-client';
import {createNetworkStatusNotifier} from 'react-apollo-network-status';
import {createHttpLink} from 'apollo-link-http';
const {
NetworkStatusNotifier,
link: networkStatusNotifierLink
} = createNetworkStatusNotifier();
const client = new ApolloClient({
link: networkStatusNotifierLink.concat(createHttpLink())
});
// Render the notifier along with the app. The
// `NetworkStatusNotifier` can be placed anywhere.
const element = (
<Fragment>
<NetworkStatusNotifier render={({loading, error}) => (
<div>
{loading && <p>Loading …</p>}
{error && <p>Error: {JSON.stringify(error)}</p>}
</div>
)} />
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</Fragment>
);
const node = document.getElementById('root');
ReactDOM.render(element, node);
You can achieve this in two ways:
One way is to use the middleware/afterware of Apollo's network interface.
The other way is to wrap Apollo's network interface to include your custom logic. Specifically you would wrap the query method.