I'm having some trouble with ESLint and arrow functions in a react component using the eslint-plugin-react plugin. I just did these commands:
npm i -g eslint eslint-plugin-react
eslint SignUpPage.jsx
And here is SignUpPage:
/**
* Created by jwilso37 on 4/5/2017.
*/
import React from 'react';
import SignUpForm from '../components/landing/SignUpForm.jsx';
import 'whatwg-fetch'
class SignUpPage extends React.Component {
constructor(props) {
super(props);
this.state = {
errors: {},
user: {
email: '',
name: '',
password: ''
}
};
}
/**
* Change the user object.
*
* #param {object} e - the JavaScript event object
*/
changeUser = (e) => {
const field = e.target.name;
const user = this.state.user;
user[field] = e.target.value;
this.setState({
user
});
};
/**
* Handles processForm event and submits request to server.
* #param e
*/
processForm = (e) => {
e.preventDefault();
const form = document.querySelector('form');
const formData = new FormData(form);
fetch('/api/signup', {
method: 'POST',
body: formData
}).then(response => {
if (response.ok) {
this.setState({
errors: {}
});
}
else {
// returned > 300 status code
response.json().then(j => {
const errors = j.errors ? j.errors : {};
errors.summary = j.message;
this.setState({
errors: errors
})
})
}
})
};
/**
* Render the component.
*/
render() {
return (
<SignUpForm
onSubmit={this.processForm}
onChange={this.changeUser}
errors={this.state.errors}
user={this.state.user}
/>
);
}
}
export default SignUpPage;
But the output of eslint is oddly this:
ubuntu#ETFly:/vagrant/client/src/containers$ eslint signuppage.jsx
/vagrant/client/src/containers/signuppage.jsx
31:16 error Parsing error: Unexpected token =
Saying that the = sign on the changeUser anonymous function is an error? Here's my .eslintrc.json:
{
"plugins": [
"react"
],
"settings": {
"react": {
"createClass": "createClass", // Regex for Component Factory to use, default to "createClass"
"pragma": "React", // Pragma to use, default to "React"
"version": "15.0" // React version, default to the latest React stable release
}
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6,
"ecmaFeatures": {
"jsx": true
}
},
"extends": ["eslint:recommended", "plugin:react/recommended"],
"env": {
"browser": true
}
}
OK I seemed to have fixed it. I installed babel-eslint with npm i --save-dev babel-eslint after I realized my JSX spread operator wasn't working as well. It made me think that all of ES6 stuff was messed up. So now I just added babel-eslint parser with adding "parser": "babel-eslint" to the end of my .eslintrc.json file and everything is good! I guess the default eslint parser doesn't support these features...
Related
I am making a NextJS React application and trying to fetch data from my server using this line:
let data = await fetch('/api/getAllAlumniInfoList').then(res => res.json())
When I run the server using next dev, everything works fine. But when I try to build the application for production using next build I get this error:
(node:173544) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/deps/undici/undici:5491
throw new TypeError("Failed to parse URL from " + input, { cause: err });
^
TypeError: Failed to parse URL from /api/getAllAlumniInfoList
at new Request (node:internal/deps/undici/undici:5491:19)
at Agent.fetch2 (node:internal/deps/undici/undici:6288:25)
... 4 lines matching cause stack trace ...
at Wc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
at Zc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
at Z (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
at Zc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:481) {
[cause]: TypeError [ERR_INVALID_URL]: Invalid URL
at new NodeError (node:internal/errors:393:5)
at URL.onParseError (node:internal/url:564:9)
at new URL (node:internal/url:644:5)
at new Request (node:internal/deps/undici/undici:5489:25)
at Agent.fetch2 (node:internal/deps/undici/undici:6288:25)
at Object.fetch (node:internal/deps/undici/undici:7125:20)
at fetch (node:internal/process/pre_execution:214:25)
at onSearch (/app/goatconnect/goatconnect/.next/server/pages/coach/alumniView.js:75:30)
at PlayersView (/app/goatconnect/goatconnect/.next/server/pages/coach/alumniView.js:103:9)
at Wc (/app/goatconnect/goatconnect/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44) {
input: '/api/getAllAlumniInfoList',
code: 'ERR_INVALID_URL'
}
}
Another strange thing about this error is I have different pages with the same exact structure using the same logic that work fine and the compiler does not complain about. I am not sure what could be causing this API route to not be recognized correctly.
I have tried to use the NextJS provided hook useSWR which works in a lot of other instances but this specific use case is for a database search so using a hook causes a infinite loop when the page is updated with the results of the API call.
useSWR is a good option but for fetch i would recommend using unfecth as a fetcher for useSWR. Worked without issues for me.
import fetch from 'unfetch'
import useSWR from 'swr'
function YourComponent() {
const { data, error } = useSWR('/api/getAllAlumniInfoList', fetch)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
An update with search input, useSWR and no infinite loop:
import { ChangeEvent, useCallback, useState } from "react";
import styles from "../styles/Home.module.css";
import fetch from "unfetch";
import useSWR from "swr";
import { debounce } from "lodash";
const fetcher = (url: string) => fetch(url).then((res) => res.json());
export default function Home() {
const [value, setValue] = useState<string>("");
const { data = [], error } = useSWR(
value ? `/api/user/${value}` : null,
fetcher,
{
fallbackData: [],
}
);
const onChange = debounce(
useCallback(
(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value),
[value]
),
500
);
if (error) {
return <div>An error occured</div>;
}
return (
<div className={styles.container}>
<input onChange={onChange} />
{data?.map((e: any) => (
<div key={Math.random()}>{e.name}</div>
))}
</div>
);
}
IMPORTANT: value cannot be passed to input. Just pass onChange method.
On API side with fake data, filepath /pages/api/user/[name].ts:
import type { NextApiRequest, NextApiResponse } from "next";
type Data = {
name: string;
};
const data: Array<Data> = [
{ name: "John Doe" },
{ name: "Miss Pierce Bogisich" },
{ name: "Beaulah Tillman" },
{ name: "Aracely Hessel" },
{ name: "Margret Berge" },
{ name: "Hailee Macejkovic" },
{ name: "Lazaro Feeney" },
{ name: "Gennaro Rutherford" },
{ name: "Ian Hackett" },
{ name: "Sonny Larson" },
{ name: "Dr. Liza Wolf" },
];
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Array<Data>>
) {
const {
query: { name },
} = req;
console.log(name);
res
.status(200)
.json(
data.filter((e) =>
e.name.toLowerCase().includes(`${name?.toString().toLowerCase()}`)
)
);
}
In vue.js. I have the following auth.js, at the bottom of the js file it has "export default". In my Registration.vue file how do I access "actions"?
This is what I have tried:
Registration.vue
import {actions} from 'src/util/auth';
export default {
components: {
actions
},
data(){
},
methods: {
submitReg() {
console.log(actions)
}
}
}
error: export 'actions' was not found in 'src/util/auth'
This is the auth.js file full code here https://gist.github.com/toricls/5c38d2930a36262f0674c1ffa8d5134a:
import Amplify, { Auth } from 'aws-amplify';
const state = {
user: null,
};
const actions = {
async getCurrentUserInfo({ commit }) {
// This is returning null - why?
// const user = await Auth.currentUserInfo();
const user = await Auth.currentAuthenticatedUser();
const attributes = await Auth.userAttributes(user);
console.log(attributes);
commit(types.AUTHENTICATE, {
username: user.username,
...extractAttributes(attributes),
});
},
async signIn({ commit }, { username, password }) {
const user = await Auth.signIn(username, password);
const attributes = await Auth.userAttributes(user);
commit(types.AUTHENTICATE, {
username: user.username,
...extractAttributes(attributes),
});
},
async signOut() {
await Auth.signOut();
},
async signUp(_, { username, password, firstName, lastName }) {
const data = await Auth.signUp({
username,
password,
attributes: {
given_name: firstName,
family_name: lastName,
},
});
console.log(data);
},
};
const mutations = {
[types.AUTHENTICATE](state, payload) {
state.user = payload;
},
[types.SIGNOUT](state) {
state.user = null;
},
};
export default {
namespaced: true,
state,
actions,
mutations,
};
There are two kinds of exports in es6 modules: named and default. When you see the braces { } in an import, that's the named import syntax. It's not the same as destructuring though it looks like it. You can't destructure inside an import statement. Change your code to:
import myExport from 'src/util/auth';
const { actions } = myExport;
Here are some examples of using both kinds of exports:
Default export examples
export default { a: 1, b: 2 } // Default object export
export default "Some string" // Default string export
Import these like:
import myExport from 'mymodule'; // no braces
Named export examples
export const myExport = { a: 1, b: 2 } // named object export
export const myExport = "Some string" // named string export
Import these like (note the braces):
import { myExport } from 'mymodule' // braces
I would imagine that this error is happening because it isn't finding the auth.js file. 'src/util/auth' is a relative path (by default in webpack) from the component file but I'm assuming (given the folder naming) that your component file isn't at the top level.
Either input the correct relative path or setup an absolute path alias within your webpack setup. This is a decent article explaining how to do this.
Hello Everyone!
In the WatermelonDB docs you can make your component reactive with withObservables() method, it will update or re-render your component every time the data changes.
In my code
I have basic user data that has been stored to WatermelonDB, and the result when I am console.log() that data is:
{
"__changes": {
"_isScalar": false,
"_value": [Circular],
"closed": false,
"hasError": false,
"isStopped": false,
"observers": [],
"thrownError": null
},
"_hasPendingDelete": false,
"_hasPendingUpdate": false,
"_isCommitted": true,
"_isEditing": false,
"_raw": {
"_changed": "",
"_status": "created",
"city": "NY City", // The data that I added
"id": "rddcv3ttt9s03jel", // The data that I added
"name": "John Doe", // The data that I added
"user_id": 0 // The data that I added
},
"_subscribers": [],
"collection": {
"_cache": {
"map": [Map],
"recordInsantiator": [Function anonymous],
"tableName": "user"
},
"_subscribers": [],
"changes": {
"_isScalar": false,
"closed": false,
"hasError": false,
"isStopped": false,
"observers": [Array],
"thrownError": null
},
"database": {
"_actionQueue": [ActionQueue],
"_actionsEnabled": true,
"_isBeingReset": false,
"_resetCount": 0,
"_subscribers": [Array],
"adapter": [DatabaseAdapterCompat],
"collections": [CollectionMap],
"schema": [Object]
},
"modelClass": [Function User]
}
}
With withObservables() method I can display that data, and here's my code:
import React, {useEffect, useState} from 'react';
import {Button, Layout} from '#ui-kitten/components';
import WATERMELON from '../models';
import util from '../utils';
import {View} from 'react-native';
import withObservables from '#nozbe/with-observables';
import {Text} from '../components/Helper';
const enhance = withObservables(['user'], props => {
return {
user: props.user,
};
});
const UserBasicInfo = enhance(props => {
// Successfully displaying the data but not Reactive
return (
<>
<Text>{props.user.name}</Text> {/* John Doe */}
<Text>{props.user.city}</Text> {/* NY City */}
</>
);
});
const TestScreen = props => {
const [user, setUser] = useState(null);
useEffect(() => {
(async () => {
await WATERMELON.action(async () => {
const user_collection = WATERMELON.collections.get('user');
const fetch_userdata = await user_collection.find('rddcv3ttt9s03jel');
console.log(fetch_userdata);
setUser([fetch_userdata]);
});
})();
}, []);
return (
<Layout>
<View>
<Text>Hello Test Screen!</Text>
{user !== null && <UserBasicInfo user={user} />}
<Button
onPress={async () => {
await WATERMELON.action(async () => {
const user_collection = WATERMELON.collections.get('user');
const userd = await user_collection.find('rddcv3ttt9s03jel');
await userd.update(user => {
// Just want to change the city
// And it's just fine BUT not reactive :(
user.city = 'Chicago';
});
});
}}
>
Press It
</Button>
</View>
</Layout>
);
};
export default TestScreen;
My models/user.model.js
import {Model} from '#nozbe/watermelondb';
import {field} from '#nozbe/watermelondb/decorators';
export default class User extends Model {
static table = 'user';
#field('name') name;
#field('city') city;
}
My models/index.js file
import fs from 'react-native-fs';
import {Database} from '#nozbe/watermelondb';
import SQLiteAdapter from '#nozbe/watermelondb/adapters/sqlite';
import schema from '../schema/watermelon.schema';
import userModel from './user.model';
import customerModel from './customer.model';
// First, create the adapter to the underlying database:
const adapter = new SQLiteAdapter({
schema,
dbName: `${fs.DocumentDirectoryPath}/restronic`, // optional database name or file system path
// migrations, // optional migrations
synchronous: true, // synchronous mode only works on iOS. improves performance and reduces glitches in most cases, but also has some downsides - test with and without it
// experimentalUseJSI: true, // experimental JSI mode, use only if you're brave
});
// Then, make a Watermelon database from it!
const db = new Database({
adapter,
modelClasses: [userModel, customerModel],
actionsEnabled: true,
});
export default db;
I dunno what's wrong with my code, I just follow the tutorial in the Docs but it's still not reactive :(
Update
I try with .subscribe() method and still not reactive and even worse it's not re-rendering the component when I setState() inside that method, The method is running well when I am trying console.log() inside that method
const UserBasicInfo = props => {
const [state, setState] = useState(props.user);
useEffect(() => {
const subscription = props.user.subscribe(newVal => {
// Not re-rendering the component
setState(newVal);
});
return () => subscription.unsubscribe();
});
return <>{state !== null && <Text>{state.name}</Text>}</>;
};
Add 'observe()' in the end, it will work
const enhance = withObservables(['user'], props => {
return {
user: props.user.observe(),
};
});
I am trying to make my 1st Relay query. I did npm run relay and npm run build. Everything works well, but in console I am getting error:
Does anybody know what may cause this error?
Update.
Table.js (component where I want make query)
import React, { Component } from 'react';
import { graphql, QueryRenderer } from 'react-relay';
const environment = import('../../environment.js');
class Table extends Component {
render() {
return (
<QueryRenderer
environment={environment}
query={graphql`
query TableQuery {
users {
data {
name
}
}
}
`}
render={({error, props}) => {
return <div>User: 1</div>;
}}
/>
);
}
}
export default Table;
environment.js (relay config)
import {
Environment,
Network,
RecordSource,
Store,
} from 'relay-runtime';
function fetchQuery(
operation,
variables,
) {
return fetch('/graphql', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
query: operation.text,
variables,
}),
}).then(response => {
return response.json();
});
}
const network = Network.create(fetchQuery);
const store = new Store(new RecordSource());
const environment = new Environment({
network,
store
});
export default environment;
Everything is from docs setup page.
In Table.js, it seems you mixed up the syntax for importing:
const environment = import('../../environment.js'); // Wrong
const environment = require('../../environment.js'); // OK
import environment from '../../environment.js'; // OK
Using import('../../environment.js') makes it a dynamic import which returns a Promise (depending on your bundler config) and is unlikely what you want.
Reusing code from a library example I got my paypal button working like a charm but now I have this warning comming from that component:
Warning: Accessing createClass via the main React package is deprecated,
and will be removed in React v16.0. Use a plain JavaScript class
instead. If you're not yet ready to migrate, create-react-class v15.*
is available on npm as a temporary, drop-in replacement. For more info
see printWarning #
lowPriorityWarning.js:38 lowPriorityWarning # lowPriorityWarning.js:57
get # React.js:106 register # checkout.lib.js:7165 Component.driver #
checkout.lib.js:5247 ./src/components/presentational/PayPalButton.js #
PayPalButton.js:6
webpack_require
so since the problem is comming from line 6 it might be the way Button is created:
const Button = paypal.Button.driver('react', { React, ReactDOM })
I tried this link provided in the warning but didn't help much and I don't know how to import it or create it differently, this is my complete code:
import React from 'react'
import ReactDOM from 'react-dom'
import paypal from 'paypal-checkout'
import PropTypes from 'prop-types'
const Button = paypal.Button.driver('react', { React, ReactDOM })
export default class PayPalButton extends React.Component {
constructor(props) {
super(props)
this.state = {
env: this.props.env,
client: {
sandbox: this.props.sandboxID,
production: this.props.productionID
},
amount: this.props.amount,
currency: this.props.currency,
commit: this.props.commit
}
}
payment(data, actions) {
return actions.payment.create({
transactions: [
{
amount: { total: this.state.amount, currency: this.state.currency }
}
]
})
}
onAuthorize(data, actions) {
return actions.payment.execute().then((payment_data)=>{
var payment = {}
payment.paid = true
payment.cancelled = false
payment.payerID = data.payerID
payment.paymentID = data.paymentID
payment.paymentToken = data.paymentToken
payment.returnUrl = data.returnUrl
// getting buyer's shipping address and email
payment.address = payment_data.payer.payer_info.shipping_address
payment.email = payment_data.payer.payer_info.email
this.props.paymentDone(payment)
})
.catch(err => {
console.log ('error PayPal'+err)
throw err
})
}
render() {
return (
<Button
commit={ this.state.commit }
env={ this.state.env }
client={ this.state.client }
payment={ (data, actions) => this.payment(data, actions) }
onAuthorize={ (data, actions) => this.onAuthorize(data, actions) }
onCancel={this.props.onCancel}
onError = {this.props.onError}
/>
)
}
}
PayPalButton.propTypes = {
env: PropTypes.string.isRequired,
sandboxID: PropTypes.string,
productionID: PropTypes.string,
amount: PropTypes.number.isRequired,
currency: PropTypes.string.isRequired,
commit: PropTypes.bool.isRequired
}