I am trying to submit a simple form in a React component:
class UploadPartList extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
console.log('Clicking submit');
$.ajax({
type: "POST",
url: "/partListUpload",
success: function(){
console.log("Post success");
},
error: function(xhr, status, error) {
console.log(error);
}
})
}
render() {
return (
<div>
<form id="csvForm" action='' onSubmit={this.handleSubmit} method='post' encType="multipart/form-data">
<p>upload your part number list (.xls or .csv)</p>
<input id="uploadCSV" type="file" name="csv_form" />
<input type="submit" className="submitButton" />
</form>
</div>
);
}
}
My routes.js file is thus:
import React from 'react';
import { Router, Route } from 'react-router';
import App from './components/App';
const Routes = (props) => (
<Router {...props}>
<Route path="/" component={App} />
</Router>
);
export default Routes;
And my Express routes in the server are defined like this:
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
});
app.use('/partListUpload', upload.single('csv_form'), partListUploadController);
app.post('/partListUpload', function(req, res) {
res.send(req.body);
});
However, when I try to submit the form, I receive a 404 error. It seems that React expects the route defined by React Router instead of a route I define in my server.
I have looked over similar StackOverflow questions and haven't found a solution that works. How can I hit a route I define on the backend?
It seems that my problem was that my Express server was not actually running. I created this app using the create react app package. I then followed this guide in setting it up with Express. However, I continued trying to get my app to work by just running npm start in the CLI instead of npm run build and then node server/index.js. Now it works.
Related
I'm trying to authenticate to Xero's API. I get a 'code' which is then exchanged for an access_token. I'm still new to NextJS and React so I'm likely not thinking about this correctly.
The code I have results in the right data being returned, however I don't know how to use it effectively in the rest of the app. I couldn't figure out how to use NextAuth in a custom provider so tried to roll my own.
The user clicks the button 'Connect to Xero' - this is a href to initiate the process and takes the user to Xero to login in the browser. User authenticates. Xero calls the callback
the callback at /api/callback responds
I extract the 'code' and then make the subsequent request to Xero to swap it for an access token.
This is where I get stuck - because the initial action is a href redirect, I'm not sure how to get the end API result back into my code as state/something usable. In effect Xero is calling the api/callback page and that's where the user is left.
I've tried to put useState hooks into the api/callback however that breaks the rule of hooks.
Any pointers greatly appreciated.
Code;
pages/index.js
import React from 'react'
import Layout from '../components/Layout'
import TopNav from '../components/TopNav'
import Link from 'next/link';
export default function Main(props) {
const test = props.URL
return (
<>
<Layout>
<TopNav name="Main page"/>
<p>this is the main page</p>
<Link href={test} passHref={true}>
<button className=' w-40 border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium sm:flex-1'>
Connect to Xero
</button>
</Link>
</Layout>
</>
)
}
export async function getStaticProps() {
const XeroAuthURL = "https://login.xero.com/identity/connect/authorize?response_type=code&client_id="
const client_ID = process.env.XERO_CLIENT_ID
const redirect_uri = process.env.XERO_REDIRECT_URI
const scope = "offline_access openid profile email accounting.settings"
const URL = `${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}`
return {
props: {
URL: URL
},
};
}
/api/callback.js
import axios from "axios"
const qs = require('qs');
export default async function callback(req, res) {
try {
//callback from Xero will deliver the code, scope + state (if given)
//https://developer.xero.com/documentation/guides/oauth2/auth-flow/#2-users-are-redirected-back-to-you-with-a-code
console.log(`REQ = ${JSON.stringify(req.query)}`)
//exchange code for tokens - https://developer.xero.com/documentation/guides/oauth2/auth-flow/#3-exchange-the-code
var data = qs.stringify({
'code': req.query.code,
'grant_type': 'authorization_code',
'redirect_uri': 'http://localhost:3000/api/callback'
});
var config = {
method: 'post',
url: 'https://identity.xero.com/connect/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic **put your authorisation result here**'
},
data : data
};
try {
const response = await axios(config)
//response has the data I want to put into State
console.log(JSON.stringify(response.data));
//save data off here somehow???
//tried redirecting but unsure if can pass the result
res.redirect(307, '/')
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
}
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
}
}
Added a not-secure cookie that I can use while testing. Do not use this in production as the cookie is not httpOnly and not secure.
import axios from "axios"
import Cookies from 'cookies'
const qs = require('qs');
export default async function callback(req, res) {
const cookies = new Cookies(req,res)
try {
var data = qs.stringify({
'code': req.query.code,
'grant_type': 'authorization_code',
'redirect_uri': 'http://localhost:3000/api/callback'
});
var config = {
method: 'post',
url: 'https://identity.xero.com/connect/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic **YOUR AUTH CODE HERE**'
},
data : data
};
try {
var response = await axios(config)
response.data.expires_at = Date.now() + response.data.expires_in*1000
//save data off
//TO DO - THIS IS REALLY BAD - ONLY USE THIS TEMPORARILY UNTIL HAVE GOT PERMSTORAGE SETUP
cookies.set('myCookieName', JSON.stringify(response.data), {
secure: false,
httpOnly: false
}
)
res.redirect(307, '/')
//return ({ data: response.data })
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
}
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
}
}
Then in the index;
import React from 'react'
import Layout from '../components/Layout'
import TopNav from '../components/TopNav'
import Link from 'next/link';
import { getCookie } from 'cookies-next';
export default function Main(props) {
//check for cookie
//TO DO THIS IS REALLY BAD; CHANGE WHEN GET PERM STORAGE ORGANISED
const cookie = getCookie('myCookieName');
const URL = props.URL
return (
<>
<Layout>
<TopNav name="Main page"/>
<p>this is the main page</p>
<Link href={URL} passHref={true}>
<button className=' w-40 border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium sm:flex-1'>
Connect to Xero
</button>
</Link>
<p>{cookie ? cookie : 'waiting for cookie...'}</p>
</Layout>
</>
)
}
export async function getStaticProps() {
const XeroAuthURL = "https://login.xero.com/identity/connect/authorize?response_type=code&client_id="
const client_ID = process.env.XERO_CLIENT_ID
const redirect_uri = process.env.XERO_REDIRECT_URI
const scope = "offline_access openid profile email accounting.settings"
//console.log(`URL - ${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}`)
const URL = `${XeroAuthURL}${client_ID}&redirect_uri=${redirect_uri}&scope=${scope}`
return {
props: {
URL: URL,
},
};
}
I need help about Axios.
I develop a SPA webapp on Laravel 6 (with package SPARK) and VueJS (version 2).
On a Vue component, I want to retrieve datas from my bdd.
So, I use Axios to make a get request on an API uri.
But, when I call Axios request, data field in Response object is a HTML code.
This is my code :
routes/web.php
Route::get('/', function(){
return view('welcome');
});
Route::middleware('auth')->get('/{any?}', function (){
return view('documents');
})->where('any', '[\/\w\.-]*');
The "welcome" view is a blade page where redirect on "/login" if user is not authenticate.
Otherwise, it redirect on "/home".
The link "/home" is define on vue-router in app.js.
The other route is the unique way to display the webapp (it's a single page application).
The Vue instanciation is in "passeport" view.
resources/js/app.js
import 'es6-promise/auto'
require('spark-bootstrap');
require('./components/bootstrap');
window.Vue = require('vue');
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
Vue.component('index', require('./components/pages/index').default);
import Dashboard from './components/pages/dashboard.vue';
...
const routes = [
{
name: 'dashboard',
path: '/home',
component: Dashboard,
},
{...}
]
const router = new VueRouter({
history: true,
mode: 'history',
routes: routes
});
var app = new Vue({
mixins: [require('spark')],
router,
});
router package is added in Vue instanciation.
it is in the same context than spark component (identify by the #spark-app element)
resources/views/documents.blade.php
#extends('spark::layouts.app')
#section('content')
<div id="app">
<index :user="user"></index>
</div>
#endsection
It is the view returned for any path.
In the spark::layout.app, there is only a div with id="spark-app" and the #yield('content').
resouces/js/components/pages/index.vue
<template>
<transition name="fade">
<Component :is="layout" :user="user">
<router-view :layout.sync="layout" :user="user"></router-view>
</Component>
</transition>
</template>
.
.
<script>
const default_layout = "default";
export default{
props: ['user'],
data(){
return{
layout: 'div',
}
},
}
</script>
It's just the vue component with the router-view configure with a layout.
resources/js/components/pages/dashboard.vue
<template>
...
</template>
<script>
import Default from './../layouts/Default.vue'
export default {
props: ['user'],
data: function () {
return {
documents: []
}
},
created() {
this.$emit('update:layout', Default);
},
mounted(){
// extract passeports's informations
this.axios.get('/api/documentslist').then(response => {
console.log(response);
this.documents= response.data.data;
});
}
}
</script>
Here, I call the documentslist API define in routes/api.php.
routes/api.php
Route::middleware('auth:api')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::get('/documentslist', 'DocumentController#list');
});
app/http/Controllers/DocumentController.php
...
public function list(Request $request){
return DocumentCollection(Document::all());
}
...
When I go to "/home", I verified "documents" data in Vue (or in the javascript console log), and response.data = "\r\n\r\n\r\n (...) v-if=\"notification.creator\" :src=\"notification.creator.photo_url\" class=... (10024 total length)"
But, list method in DocumentController have to return a list of documents, and not a HTML code.
Furthermore, I use Passport Laravel to unified authentication by login and the API token.
And the Axios request work in the same project without SPA structure.
I hope I'm clear in the problem explanation, and that I forget any detail to understand.
Thanks.
You can simply return like this from your controller
return response()->json(Document::all());
I suspect the API link to redirect with the SPA route (in routes/web.php, any path return the "home" view).
I try to change route in routes/web.php.
instead of :
Route::middleware('auth')->get('/{any?}', function (){
return view('home');
})->where('any', '[\/\w\.-]*');
I put this :
Route::middleware('auth')->get('/home', function (){
return view('home');
});
Like this, this route doesn't take account of all path.
And...it works !
But...it isn't what I want :(
Indeed, without the route with '/{any?}' the SPA doesn't work.
I don't understand why this method works another project in Laravel (without Spark package), and doesn't work with this project.
I don't know about laravel but this problem arises when the route you are calling is not the correct one. Do some efforts and check what route the application in eventually calling also take a look at your proxy settings.
****I am NodeJs developer not Laravel
I have Laravel in api folder and Vue is in the root folder, and I try to pass data from Laravel to Vue Components.From what I find I must use axios for this but I didn't know how. I am looking for a solution for some hours now, but nothing worked. PS. I didn't do anything in blade till now. Any help, please !?
api/routes/api.php
Route::get('/content', 'ContentController#index');
ContentController
public function index() {
$customers = Customer::all();
return $customers;
}
Vue component
<template>
</template>
<script>
import axios from 'axios'
export default {
name: "Home"
};
</script>
Since you created your Vue app using the Vue CLI, running vue serve starts your application at a local URL, you need to have your Laravel API app running as well so you can request data from it using Axios in Vue components
cd api
php artisan serve
Then in your template, you should have something like this
<template>
<div></div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
databaseConfiguration: "",
errors: {}
};
},
name: "Home",
created: function() {
axios
.get("http://127.0.0.1:8000/api/content")
.then(response => {
this.databaseConfiguration = response.data;
console.log(response.data);
})
.catch(error => {
this.errors.push(error);
console.log(error);
});
}
};
</script>
Here's a full working example app on GitHub
Hope this helps
i have also reffered the documentation of react_hooks but it was of no help so plz help me with this code
actions/forgetpassword.js
import axios from "axios";
import {setAlert} from "./alert";
//find email in database
export const forgetpassword = ({email}) => async dispatch => {
const body = JSON.stringify({email});
try {
const res = await axios.post('/api/otp/forgetpassword', body);
dispatch({
type: EMAIL_FOUND,
payload: res.data
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: EMAIL_ERROR
});
}
};
there is an error in making funtion it says function is not the hook function not the custom hook function
forgetpassword.js
it says error is in this file
import React, {Fragment, useState} from 'react';
import {Link, Redirect} from "react-router-dom";
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {forgetpassword} from '../../actions/forgetpassword';
const forgetPassword = ({forgetpassword}) => {
const [formData, setformData] = useState({
email:''
});
const {email} = formData;
const onChange = e => setformData({...formData, [e.target.name]: e.target.value});
const onSubmit = async e => {
e.preventDefault();
console.log('SUCCESS');
forgetpassword(email);
};
return (
<Fragment>
<h1 className="large text-primary">Sign In</h1>
<p className="lead"><i className="fas fa-user"></i> Sign Into Your account</p>
<form className="form" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="email" placeholder="Email Address" name="email" value={email}
onChange={e => onChange(e)}/>
</div>
<input type="submit" className="btn btn-primary" value="Login"/>
</form>
</Fragment>
);
};
forgetPassword.prototype = {
forgetpassword: PropTypes.func.isRequired,
};
export default connect(null, {forgetpassword})(forgetPassword);
error
Line 8: React Hook "useState" is called in function "forgetPassword" which is neither a React function component or a custom React Hook function```
I have attached all the code related to error so if any body knows the problem tell me
The issue seems to be that the component name is not starting with a capital letter.
React recognizes it as a function rather than a component and it throws that error.
I've created the most basic react app possible and am trying to do a simple GET request. It throws a TypeError and states, 'name.toUppercase is not a function'. I only have the one function. Any ideas what is causing this or how to debug?
import React, { Component } from 'react';
import axios from 'axios';
import logo from './logo.svg';
import './App.css';
class App extends Component {
state = {
order_id: Number,
order_date: '',
size: '',
crust: '',
toppings: [],
};
componentDidMount() {
return axios
.get('https://59b6v76zci.execute-api.us-west-
2.amazonaws.com/nr/example', {
method: 'GET',
mode: 'cors',
headers: 'Access-Control-Allow-Origin',
})
.then(response => this.setState({ order_id: response.order_id }))
.catch(err => console.log('err', err));
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
This is the what is returned in the console
err TypeError: name.toUpperCase is not a function
at processHeader (normalizeHeaderName.js:7)
at Object.forEach (utils.js:218)
at normalizeHeaderName (normalizeHeaderName.js:6)
at transformRequest (defaults.js:32)
at transform (transformData.js:16)
at Object.forEach (utils.js:224)
at transformData (transformData.js:15)
at dispatchRequest (dispatchRequest.js:37)
at <anonymous>
Try changing your axios request to this:
axios
.get('https://59b6v76zci.execute-api.us-west-2.amazonaws.com/nr/example', {
method: 'GET',
mode: 'cors',
headers: { 'Access-Control-Allow-Origin': true },
})
.then(response => this.setState({ order_id: response.data.order_id }))
.catch(err => console.log('err', err));
You got two things wrong - headers should be an object, and the data in the response should be under response.data.
Also, on a side-note, Access-Control-Allow-Origin header usually comes as a response header and not on the request.