react: how to pass in URLs for REST APIs - javascript

Starting to learn react and couldn't find the answer to this on the internet. Maybe I don't know what terms to use.
My backend is django and I want to be able to pass in URLs for REST APIs to my React front end.
I don't want to hard code them in react as they are already defined in django.
It makes sense to me that I would want to render a script tag on my html template that contains an object containing the URL values.
e.g. the django template would have something like
<script type="text/javascript">
var CONFIG = {
some_url : '{% url "my-api" %}'
}
</script>
(for those not familiar with django, that {% url %} tag renders a url like /path/to/myapi)
Then in my React Stores/Actions I would just refer to CONFIG.some_url.
Is this the right way to do it? Or is there a better way to make this information available to my react components.
------------ Edit -----------------
Using webpack to transpile the jsx files and using django-webpack-loader to integrate everything. this means that the django templates are completely rendered before the jsx is loaded on top.
As a result the template tags cannnot run inside the jsx files.

Even though you're using django-webpack-loader(I am too), you still can pass props to your React app. You can proceed like this:
1) Resolve the absolute backend url in your view.py:
def get_context_data(self, **kwargs):
context['APIROOT_URL'] = reverse('api-root', request=self.request)
return context
2) Pass the context prop to the html template
<div id="react-app"></div>
<script>
window.__APIROOT_URL__= '{{ APIROOT_URL }}';
window.react_mount = document.getElementById('react-app');
</script>
{% render_bundle 'main' %}
3) Finally inside your app, get the property like this:
const apirootUrl = window.__APIROOT_URL__

pass it as props:
<MyComponent src={% url %} />

Put following plugin in your webpack configuration:-
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.environ),
}
})
],
Run the webpack command as follows:-
environ=local webpack
or
environ=production webpack -p //for production
Create a constants file where you keep a function which returns API
urls based on environment variable set above.(local,dev,production).
const api_url=function(){
let api_url=//production api url
if(process.env.NODE_ENV == 'local'){
//local api url
}
else if(process.env.NODE_ENV == 'development'){
//dev api url
}
return api_url;
}
export const url= api_url();
Import this in your componentDidMount() call the api using ajax/fetch/axios
import {url} from ../constants
componentDidMount(){
//api call
}
If you are using django and react together I would strongly suggest to look at django-webpack-loader once

Related

env variables as arguments to react application

I have a ready React application that I would like to distribute as a link to any HTML page, such as:
<script src=".../app.js"></script>
and later call some function, for example App.create(document.getElementById('root')) that would render my app in the provided HTML element.
The problem is that my app uses process.env variables for storing for example API URL, so ideally in fact I would like to call
App.create(document.getElementById('root'), {
apiUrl: ...
})
// create function, index.ts
export const create = (root: HTMLElement, options: Options) => {
ReactDOM.render(<App />, root);
};
Later in the app code there is a eg. line const apiUrl = process.env.API_URL
My question: Is there a way to make api url an argument of App.create instead of process.env variable without introducing major changes to the code? Esentially is it possible to move .env contents to App.create(.env)

How to create a global string in a vue (webpack) project

In my vue project I have a default image that should show up in places around the app when an image is missing or hasn't been uploaded yet. I have various class files and component calls that want to use the same image.
What is the best way to create a global variable that I can access from anywhere? I can't put it in the store because my class files (I'm using vuex-orm) are loaded before the store is declared. I would prefer not to put it in the window because I want to have a single word variable that I can call (defaultImg as opposed to window.my_project.globals.defaultImg). I could put it in .env but I want this to be checked into the repository and the same across environments so that doesn't seem right either.
What is the best way to provide a simple global string to all files in my vue project?
Are you using Vue 2 or 3? TL;DR best approach is to create a component.
Quick Fix
You could take the approach described in the documentation for creating plugins:
https://vuejs.org/guide/reusability/plugins.html#introduction
If you didn't want to go down the convoluted route of creating a separate plugin file just to store a single string you could probably just do something like this in your entry file where you initialize the app:
Vue 3:
app.config.globalProperties.$defaultImg = '/path/to/image.png'
Vue 2:
Vue.prototype.$defaultImg = '/path/to/image.png'
And use this in your templates like
<img :src="$defaultImage">
Best Solution
However, I think the best and the most 'Vue' way would be to create an image component which displays a given image, or the default image if src is nullish:
Vue 2 & 3
<template>
<img :src="srcOrDefault">
<template>
Vue 3 Composition API:
<script>
const defaultImg = '/path/to/image.png'
const props = defineProps({
src: String
});
const srcOrDefault = computed(() => {
return props.src || defaultImg
})
</script>
Vue 2 & Vue 3 Options API:
<script>
const defaultImg = '/path/to/image.png'
export default {
props: {
src: String
},
computed: {
srcOrDefault() {
return this.src || defaultImg
}
}
}
</script>

how to use raw html file in nuxt(vue)?

I want to create a page Jump to the stripe payment page use stripe-samples/firebase-subscription-payments .
so I placed it's html/css/js file(which in the "public" folder) to my nuxt app's /static.
However, since it is for static files only, so vuex and plugins could not be used. Fortunately, the tag in html reads firebase from the url, so it is possible to use firebase.
but can I put raw html/css/js files to nuxt/pages like .vue file?(I tried but couldn't..)
I know the best way is to rewrite the html/js file into vue file, but it was too difficult for me as a beginner(Also, I'm Japanese and I'm not good at English,sorry).
or can I use npm package and module in /static/files ?
I have google it for two days and couldn't resolve it.I really need help,thank you!!
here is my code:
static/public/javascript/app.js
import firebase from firebase;
/*↑ it will be error "Cannot use import statement outside a module".
but in pages/.vue files and plugins/files, it will work...
I also tried "import firebase from '~/plugins/firebase.js'"*/
const STRIPE_PUBLISHABLE_KEY = ....
static/public/index.html
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase-functions.js"></script>
<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>
↑ it read firebase from url, but I want use firebase module I've installed.
Eventually I rewrote the js / html code to vue. Basically it is completed just by copying the js code to mounted(), but since I could not manipulate the nested template tag with js, I rewrote a part using v-if and v-for.
There are several solutions for this.
To load 3rd party scripts, you can use the following solution: https://stackoverflow.com/a/67535277/8816585
Depending on what you're trying to load, using Nuxt plugins can also be a solution: https://nuxtjs.org/docs/2.x/directory-structure/plugins/
Lastly, here is a solution on how to properly handle Stripe in Nuxt: https://stackoverflow.com/a/67504819/8816585
But static is not a place to put your code in. As told, this is for public stuff like favicons, some free pdf book that you want to share to your visitors or alike.
Didn't use firebase with Nuxt lately but those can still probably help figuring out how to write it in Nuxt, I hope.
you can load the html by render() in your vue-component-file
nuxt.config.js
build: {
extend(config, ctx){
config.resolve.alias['vue'] = 'vue/dist/vue.common';
}
}
in your vue-component-file
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`
});
}
}
</script>
and the page will be rendered as a component in your vue <router-view/> or <nuxt/>, but make sure there is no <script> tag in your my_html.html, put your js code inside the render() like below
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`,
created(){
console.log('I have been created!')
},
mounted(){
console.log('I have been mounted!')
},
methods: {
exampleMethod(){
alert('this is an example')
}
}
});
}
}
</script>

Pass data from blade file directly to Vue instance

I am working on a Vue application that's living in a Laravel project. I bind my vue instance to an id that's placed in a blade file.
What I would like to do is to pass the logged user to my Vue instance from Laravel/blade. Is there a way to do this? I know you can pass data through props but this here is just a regular div with an id of #root that's binding the Vue instance. I know how to get the logged user, but I am specific looking for an way to directly pass the data from blade to my vue instance.
app.js
// Require the deps from laravel (jQuery, axios, Bootstrap)
require('./bootstrap');
// Import vue deps
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
// Import the router & routes
import router from './routes'
// Init a new vue instance
const root = new Vue({
el: '#root',
data: {
User: name here..
},
router
});
Blade
#extends('layouts.app')
#section('content')
<!-- pass user below -->
<div id="root"></div>
#endsection
In your blade file, pass the logged user information to a javascript global variable. Let's say you just want the user id and name:
<script>
window.auth_user = {!! json_encode([
'id' => auth()->user()->id,
'name' => auth()->user()->name
]) !!};
</script>
Then in your javascript, you can access the auth_user global variable.
For example, to log the user name:
console.log(auth_user.name)
or
console.log(window.auth_user.name)
You have few options (I think I not list all) e.g:
You can pass data by converting them to json and write as HTML element or attribute and then read it from vue using e.g. document.querySelector(...) - more info here: Best way to store JSON in an HTML attribute?
You can change a littlebit architecture and create separate (Restful) API which your vue components will be use via ajax to read data (e.g. you can create GET api/v1/currentUser do read current logged user)
Completly change your architecture - to "microservices" - so in laravel only create Restful API, and creatte SEPEARATE project with vue (and NO laravel) user interface which use that API (it is modern approach to separation backend from frontend). You will face CORS problem in this approach but its no so hard (only at first time).
You might want to take a look at the PHP-Vars-To-Js-Transformer
package. You can use it either in your controller or in a #php directive.
Probably not a good practice with VueJS though.

Accessing $route.params in VueJS

Looking through this documentation:
https://router.vuejs.org/en/essentials/navigation.html
It looks like you can bind the <router-link :to="variableName">Link Text</routerlink> Which is pretty nifty; however, I've had some trouble trying to access route parameters inside of a component I'm trying to build.
So I use this:
<router-link :to="permalink">Title of thing</router-link>
To then direct the router view to pull the forum thread. Using this in the router:
import ForumThread from './views/groupTitle/forumThreadSingle';
// Other routes...
let routes = [
{
path: '/groupTitle/th/:id',
component: ForumThread,
}
];
I can see in the forumthread component that $route.params.id is being passed too it; however, when I try to access it like this:
console.log('The id is: ' + $route.params.id);
It's unable to find the params portion of the object.
VueJS is pretty new to me as well as JavaScript itself. All the examples I've seen show the templates being inline with the router file which is something I am trying to prevent to help keep my code readable and clean.
What adjustments can I make so that I can pass properties to the template file?
Thanks!
If you're using the Vue Loader setup (which has <template></template> tags in the files), you need to use this to reference the $router, if you're doing so within the <script></script> part of the file.
console.log('The id is: ' + this.$route.params.id);
For and one wanting to get params in vue 3 with composition API for vue-router 4.x, it can be achieved using useRoute.
import {useRoute} from "vue-router";
setup(){
const route = useRoute();
const id = route.params.id;
}

Categories

Resources