A large number of problems with React, Django, Django REST and Axios - reactjs

This post is the first part of the following series -
A large number of problems with React, Django, Django REST and Axios
Products on the homepage are not being displayed properly (Django, Django Rest and React)
(React and Django) Displaying products on the homepage is working fine, but when I click on any particular product, then the rendering is wrong
I am going through a very good course about setting up an e-shop, but I have reached the stage, where I am not that much sure, what is the exact purpose of the code, which I have written. (especially the async function in HomeScreen.js) We are using React and Django. My issue is related to the homepage or HomeScreen.js file, which was working fine, when I was loading the products from the static products.json file, but later on, in the course, we had to switch this and load the products from an API using Django REST and Axios (axios was used to remove the CORS error) and my problem now is, that I am not able to load the products to the HomeScreen.js and all I see is a blank page with the header instead of a full page. I am running the react server through the npm start command (the result of that can be seen on the screenshots below) but I also tried to run the Django server, which gives me this error - OSError: [WinError 123]. (Note: the Django server was fixed and is now running - so when I want to display the website, I am running React server and Django server simultaneously)
Please let me know if You can see some solution to these problems. Thank You very much for any help in advance.
The page looks like this -
And it should look like this -
(Note: this problem with displaying of the products was solved by modyfying the urls.py in the base (app) folder -
from django.urls import path
from . import views
urlpatterns = [
path('', views.getRoutes, name="routes"),
path('products/', views.getProducts, name="products"),
path('products/<str:pk>/', views.getProduct, name="product"),
]
was changed to
from django.conf.urls import url
from . import views
urlpatterns = [
url('products/', views.getProducts, name="products"),
url('products/<str:pk>/', views.getProduct, name="product"),
url('routes/', views.getRoutes, name="routes"),
]
)
When I am looking to my console, I am getting a lot of errors such as - (not all of these errors
are harmful, because for example the one relating to the collapseOnSellect was there even in the before all of the other errors have shown up and everything was working fine)
127.0.0.1:8000/api/products/:1 Failed to load resource: net::ERR_CONNECTION_REFUSED
Here are more details about the third error in the console -
(Note: This error has vanished after solving the following (path related and rest related) errors)
Another problem is, that VSCode is giving me these 2 errors - No name 'path' in module 'django.urls' and No name 'include' in module 'django.urls' (these errors are related to the both urls.py files)
(Note: these errors were solved by changing path to url (in both urls.py files) and changing from django.urls import url, include to from django.conf.urls import url, include in the project´s urls.py file and changing from django.urls import url to from django.conf.urls import url in base application´s urls.py file)
and I am getting 2 additional errors in the views.py - Unable to import 'rest_framework.decorators' and Unable to import 'rest_framework.response'. I do not know, why am I getting so many errors, because I am trying to follow every step in the tutorial.
(Note: these two errors were solved in conjuction with this SO post -
Can't import: 'unable to import rest_framework' when importing serializer? (windows))
I am sorry, if my description of the problem is not exact, because I am still just a beginner when it comes to Django and React and so on. But I might explain to You further if You ask me the right questions. I have installed Axios accordingly to the tutorial and I have integrated it into the settings.py file.
Both of the frontend and backend folders are situated in the same folder.
HomeScreen.js -
import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import Product from "../components/Product";
import axios from "axios"
function HomeScreen() {
const [products, setProducts] = useState([])
useEffect(() => {
async function fetchProducts() {
const { data } = await axios.get('http://127.0.0.1:8000/api/products/')
setProducts(data)
}
fetchProducts()
},[] )
return (
<div>
<h1>Latest Products</h1>
<Row>
{products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
</div>
);
}
export default HomeScreen;
views.py -
from django.shortcuts import render
from django.http import JsonResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .products import products
# Create your views here.
#api_view(['GET'])
def getRoutes(request):
routes = [
'/api/products/',
'/api/products/create/',
'api/products/upload/',
'api/products/<id>/reviews/',
'api/products/top/',
'api/products/<id>/',
'api/products/delete/<id>/',
'api/products/<update>/<id>/',
]
return Response(routes)
#api_view(['GET'])
def getProducts(request):
return Response(products)
#api_view(['GET'])
def getProduct(request, pk):
product = None
for i in products:
if i['_id'] == pk:
product = i
break
return Response(product)
urls.py in the base (app) folder -
from django.urls import path
from . import views
urlpatterns = [
path('', views.getRoutes, name="routes"),
path('products/', views.getProducts, name="products"),
path('products/<str:pk>/', views.getProduct, name="product"),
]
urls.py in the project folder -
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('base.urls')),
]

import React, { useState, useEffect } from "react";
import { Row, Col } from "react-bootstrap";
import Product from "../components/Product";
import axios from "axios"
function HomeScreen() {
const [products, setProducts] = useState([])
useEffect(() => {
async function fetchProducts() {
const responce = await axios.get('http://127.0.0.1:8000/api/products/')
.then((data) => setProducts(data.data)
)}
fetchProducts()
},[] )
return (
<div>
<h1>Latest Products</h1>
<Row>
{products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
</div>
);
}
export default HomeScreen;

Related

Error when navigating to `/blog` in next.js project

The Problem:
I'm building a blog with Next and sanity. When navigating to /blog, i'm encountering this error in the browser:
./sanity.js:2:0
Module not found: Can't resolve '#sanity/image-url'
1 | import { createCurrentUserHook, createClient } from "next-sanity";
> 2 | import imageUrlBuilder from "#sanity/image-url";
3 |
4 | export const config = {
5 | // Find your project ID and dataset in 'sanity.json' in your studio project.
Import trace for requested module:
./pages/blog.tsx
https://nextjs.org/docs/messages/module-not-found
The folder structure is:
root
-> components
-> pages
-> post
-> [slug].tsx
-> index.tsx
-> blog.tsx
-> sanity subfolder
-> public
-> styles
sanity.js (config file)
The sanity config file
I have a sanity config file, which exports some helper functions. One of which, is the imageUrlBuilder function, which i'm assuming the error is coming from. Here is my sanity config file: Note: this is pulled from sanity docs.
import { createCurrentUserHook, createClient } from "next-sanity";
import imageUrlBuilder from "#sanity/image-url";
export const config = {
// config info here
};
// Set up the client for fetching data in the getProps page functions.
export const sanityClient = createClient(config);
// Builder function to combo with urlFor function.
const builder = imageUrlBuilder(sanityClient);
// Helper function to generate urls from sanity photos.
export const urlFor = (source) => {
return builder.image(source);
};
The helper function was working in a previous version, and was able to pull images from sanity and display in the document. But i'm unsure why it's causing issues with page routing.
The blog page component:
import React from "react";
import BlogPreview from "../components/BlogPreview";
import { getAllPosts } from "../queries";
import { sanityClient } from "../sanity";
import { Post } from "../typings";
interface Props {
posts: [Post];
}
// required for server-side rendering. returns 'props' object from db.
export const getServerSideProps = async () => {
let query = getAllPosts;
const posts = await sanityClient.fetch(query);
return {
props: {
posts,
},
};
};
function blog({ posts }: Props) {
return (
<div>
<div className='md:grid md:grid-cols-2'>
{posts.map((post) => {
return (
<BlogPreview
key={post._id}
title={post.title}
description={post.description}
mainImage={post.mainImage}
slug={post.slug}
/>
);
})}
</div>
</div>
);
}
export default blog;
I've tried:
Logging sanity data to the console to check for config errors.
Googling the error: Module not found: Can't resolve '#sanity/image-url'
Conclusion
I'm unsure what the issue is, and how I can potentially solve it. Would love some ideas.
Thanks in advance
It sounds like you don't have the #sanity/image-url module installed in your project.
Run this in your project directory and you should be good to go!
npm install --save #sanity/image-url

React telling me my variable is undefined when I try to display list contents

I've been trying to display the contents of a list using JSX in React. My server side is flask and serves JSON data to the react frontend. When I provide JSON data with only a simple dictionary with string keys and values, react can display it just fine, but when I try to use a list, and I've been messing around with this for 15 hours now, it just keeps saying "Uncaught TypeError: initialData.names is undefined". This error is consistent across different mehthods of requesting the data. If I choose to display initialData.names, there is an error that JSX can't display an object with keys of "name". But as soon as I try to access the data inside, it freaks out. I've never used Stack Overflow before so let me know if my question needs a different format.
routes.py
import json as JSON
from flask import render_template, jsonify
from api import app
from api.static import variables as VARS
#app.route("/regions")
def regions():
print("REGIONS")
'''
data = {"data":[{
"name": region_name,
"url": "/regions/" + region_name
} for region_name in VARS.region_names]}
'''
'''
data = {
"name":"ford"
}
'''
data = {
"names":[{"name":"ford"},{"name":"toyota"}]
}
return data
Regions.js --gets run from the main js file
import React, {useEffect, useState} from 'react'; //ES6 js
import {Link, useParams} from 'react-router-dom'
function Regions(){
const [initialData, setInitialData] = useState([{}]);
useEffect(() => {
fetch('/regions').then(
response => response.json()
).then(
data => setInitialData(data)
)
});
return(
<div>
<h1>Select a Region</h1>
{initialData.names.map(brand => (<h2>{brand.name}</h2>))}
</div>
);
}
export default Regions;
Js Error

How to properly secure API login credentials with environment variables using React and Django

I have a project using React (frontend) and Django Rest Framework (backend), and it is currently deployed on PythonAnywhere. I'm using axios to connect to my API and load data from my database onto the React frontend.
During development, I hardcoded the username and password for accessing the database into my index.js file (credentials are obscured below):
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import axios from 'axios';
import 'semantic-ui-css/semantic.min.css';
import 'lightgallery.js/dist/css/lightgallery.css';
import './styles.css';
import * as serviceWorker from './serviceWorker';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true;
axios.post('/login/', { username: [HARD_CODED_USERNAME], password: [HARD_CODED_PASSWORD] }).then(rv => {
console.log('Login', rv)
}).catch(err => {
console.log('Login error', err.response)
});
const updatePhoto = () => {
axios.patch('https://[WEBSITEADDRESS.COM]/api/photos/').then(resp => {
console.log('Update response', resp)
}).catch(error => {
console.log("Update error", error)
})
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
serviceWorker.unregister();
This works, however the username and password are viewable upon inspection in the browser. Not only that, but the Django admin as well as the API is accessible to anyone, because it automatically logs them in using my username and password!
I then tried using an .env file located at the root of my create-react-app project (same level with my package.json file):
REACT_APP_USERNAME=myusername
REACT_APP_PASSWORD=mypassword
And I updated my index.js file to as follows:
const my_user_name = process.env.REACT_APP_USERNAME;
const my_password = process.env.REACT_APP_PASSWORD;
axios.post('/login/', { username: my_user_name, password: my_password }).then(rv => {
console.log('Login', rv)
}).catch(err => {
console.log('Login error', err.response)
});
However, this still does not obscure the credentials from inspection in the browser, and, while it does solve the issue of automatically logging anyone into my Django admin and API, the data from the database is not shown on the website.
My questions are as follows:
How do I properly set up axios to access my API and display data on my website WITHOUT logging someone into my Django admin?
How do I properly set up environment variables in React to hide sensitive data when using the browser's inspection tools?
Any help is much appreciated!
UPDATE: SOLUTION
Based on #Lior_Pollak's comment on his answer below, I managed to solve both of my issues by creating a public, read-only API endpoint on the backend. Anyone can view the API but cannot post, update, or delete data, nor can they access the Django admin. And no sensitive data is displayed in the browser's inspection tool, yet all my photos are displayed on the website. :)
In case anyone else stumbles across this question, I've provided the code I've used successfully below (both backend and frontend):
Frontend: index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App.js';
import 'semantic-ui-css/semantic.min.css';
import 'lightgallery.js/dist/css/lightgallery.css';
import './styles.css';
import * as serviceWorker from './serviceWorker';
/*Removed all code related to axios; was not needed here*/
ReactDOM.render(
<App />,
document.getElementById('root')
);
serviceWorker.unregister();
Backend: views.py
from django.views.generic import View
from django.http import HttpResponse
from django.conf import settings
from rest_framework import generics
from rest_framework import permissions
from .models import Photo
from .serializers import PhotoSerializer
import logging
import os
class PhotoList(generics.ListCreateAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Photo.objects.filter(show=True).order_by('order')
serializer_class = PhotoSerializer
class FrontendAppView(View):
def get(self, request):
print (os.path.join(settings.REACT_APP_DIR, 'build', 'index.html'))
try:
with open(os.path.join(settings.REACT_APP_DIR, 'build', 'index.html')) as f:
return HttpResponse(f.read())
except FileNotFoundError:
logging.exception('Production build of app not found')
return HttpResponse(status=501)
Backend: urls.py
from django.conf.urls import include, url
from rest_framework import routers
from backend import views
router = routers.DefaultRouter()
urlpatterns = [
url(r'^api/', include(router.urls)),
url(r'^api/photos/$', views.PhotoList.as_view()),
]
You are trying to obscure client data, which (for obvious reasons) resides in the client.
So you can't really obscure it.
You can force the user to login with their credentials, which is how authentication using username and password is done.

Loading gltf in gatsby site with react-three-fiber

I've been trying to load a GLTF model into my gatsby site using react-three-fiber, but can't seem to get it to load. This seems like it should be very simple, but I'm new to Gatsby and threejs and was wondering if I could get some guidance.
My model is stored as static/models/crerar.glb, and I used gltfjsx to generate a Model component. I've tried referencing just 'models/crerar.glb' but haven't had luck either.
In index.js, I have:
import Layout from "../components/layout"
import SEO from "../components/seo"
import React, { Suspense, useRef, useState } from "react"
import { Canvas, useFrame, useLoader } from "react-three-fiber"
import Model from "../components/Crerar"
const IndexPage = () => (
<Layout>
<Canvas>
<ambientLight intensity={0.2} />
<Model />
</Canvas>
</Layout>
)
export default IndexPage
and in Crerar.js (stored in components)
/*
auto-generated by: https://github.com/react-spring/gltfjsx
*/
import * as THREE from 'three'
import React, { useRef } from 'react'
import { useLoader } from 'react-three-fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
export default function Model(props) {
const group = useRef()
const { nodes, materials } = useLoader(GLTFLoader, '../static/models/crerar.glb')
return (
<group ref={group} {...props} dispose={null}>
<mesh material={nodes.mesh_0.material} geometry={nodes.mesh_0.geometry} />
</group>
)
}
the path is wrong. the json.parse error you're getting is because the loader tries to parse a HTML 404 fetch-error as a GLTF. you can make sure by opening dev tools and the networking tab. you should see it's trying to reach your file, but can't.
if the model is within your src folder you have to import it first, then use the hashed url that you get. this is my recommendation, don't mess around with public files, always import your stuff. it's safer, the compiler will complain if the file isn't present, and it's better for cache control.
otherwise, if the file is inside /public or i guess it's /static in gatsby (?) then the url has to be something like "/file.glb". sometimes it's /public/file.glb or /static/file.glb, it depends on your bundling environment (you can try fetching the file via the browsers url bar, if an url works, that's the one you should pass on to the loader).
if your file is draco compressed, then draco must also be inside public or static. see: https://codesandbox.io/s/r3f-ibl-envmap-simple-y541h
you can safely use useLoader(GLTFLoader, url), it's just a wrapper around new GLTFLoader().load(url, data => ...) + suspense. It's not experimental any longer, even though it may have that warning on Github.
gatsby copies everything from static into the public folder, so change your url to:
const { nodes, materials } = useLoader(GLTFLoader, '/models/crerar.glb')

react-pdf cors to gcp storage

I want to get pdf file from my GCP , but I get CORS error. Ok , np . I've tried to find how to solve this issue in GCP . Found this example :
https://bitmovin.zendesk.com/hc/en-us/articles/360000059353-How-do-I-set-up-CORS-for-my-Google-Cloud-Storage-Bucket-
I've following all of this instructions :
echo '[{"origin": ["*"],"responseHeader": ["Content-Type"],"method": ["GET", "HEAD"],"maxAgeSeconds": 3600}]' > cors-config.json
gsutil cors set cors-config.json gs://booknote-pdf-files-store
import React, { useState } from 'react'
import { Document, Page } from 'react-pdf'
import { withStyles } from '#material-ui/styles'
import PropTypes from 'prop-types'
import CircularProgress from '#material-ui/core/CircularProgress'
import styles from './styles'
const Application = ({ classes }) => {
const [numPages, setNumPages] = useState(null)
const [pageNumber, setPageNumber] = useState(1)
const onDocumentLoadSuccess = ({ numPages }) => {
setNumPages(numPages)
}
return (
<div className={classes.container}>
<Document
file="https://storage.cloud.google.com/booknote-pdf-files-store/living_in_the_light.pdf"
onLoadSuccess={onDocumentLoadSuccess}
renderMode="svg"
loading={<CircularProgress />}>
<Page pageNumber={pageNumber} />
</Document>
</div>
)
}
Application.propTypes = {
classes: PropTypes.instanceOf(Object).isRequired,
}
But i still get CORS error. What am I doing wrong ? If you need additional info , pls let me know
Also you can check npm package which I use for this purpose :
https://www.npmjs.com/package/react-pdf
Assuming that the gsutil command for setting up cors actually worked ( I'd double-check just to be sure, run: gsutil cors get gs://booknote-pdf-files-store and see if the changes have been reflected ). Simply put, react-pdf relies a lot on PDF.js and so it is possible that this is caused by how PDF.js gets the file from the server.
Taken straight from PDF.js FAQ, "PDF.js runs with the same permissions as any other JavaScript code, which means it cannot do cross origin requests".
There are a few workarounds available at your disposal though, one of them is using a proxy that return the Access-Control-Allow-Origin header if it's not at the Same Origin. Thus, your request for the file will not be sent to GCS but will be made to your proxy which will forward them to GCS. I highly giving PDF.js' FAQ a read, surely it will point you in the right direction.

Resources