Laravel + React: Handling API Data - javascript

I'm new to react and laravel and I am trying to boost my skills during this god awful lockdown. I'm following tons of tutorials but I keep finding that they are either incomplete, have very bad english or not indepth enough and skip over things too quickly.
I don't mean to sound ungrateful, I love the fact people are sharing this information I am just really struggling to get to grips.
I am hoping someone can help me understand how to make all these components work together. I'll explain my project:
My Project
Laravel
React
JS Charts
Bootstrap
I am creating a very basic crypto currency dashboard. That will display a chart and a table of data.
Here is a wireframe:
I have created the following componenets:
sidebar
charts
table
These are referenced in the welcome.blade.php file:
return (
<div className="example">
<SideBar />
<Chart />
<Table />
</div>
);
I also created a Laraval API that links to my sqlite database. The sidebar displays a list of the crypto currencies I have in the database.
In the sidebar:
I am calling the endpoint of /crypto I get a returned JSON. This contains a list of all the cryptos in my database (only top 10 at the moment).
componentDidMount() {
fetch('/api/crypto')
.then(response => {
return response.json();
})
.then(crypto => {
this.setState({ crypto });
});
}
and then I am adding it to the state:
constructor() {
super();
this.state = {
crypto: [],
};
}
Then I am doing rendering that into a list item.
I am doing the same from the chart and the table however, they only get a specific crypto from the endpoint /api/crypto?coin=btc.
All this works fine, the data is shown in the table, the charts show correctly.
What I want to do.
I want to be able to click any of the crypto names in the sidebar, and have the chart and table data update with that specific data.
I want to be able to reduce the amount of API calls so that if I do not have to request the database 10 times
I would be extremely grateful for details answers, links and references to videos - tutorials etc...
Thank you

Firstly, I suspect that your welcome.blade.php is not where you have your
return (
<div className="example">
<SideBar />
<Chart />
<Table />
</div>
);
That is usually in a .js file.
What you need to do is something referred to as 'lifting up the state'.
This means that you take the state from your individual components, and move them up to a wrapper component.
In your App.js file. It could still be called Example.js if you have not changed it. This is where you will see the:
return (
<div className="example">
<SideBar />
<Chart />
<Table />
</div>
);
Take out all the references for state and the functions in your sidebar, chart,table component.
Add that stuff to the App.js file.
Now, when you want to pass info to those components you send them as props.
For example:
return (
<div className="example">
<SideBar tickers={tickers}/>
<Chart data={data} />
<Table data={data}/>
</div>
);
These then become what is known as Controlled Componenents and they are stateless. They only rely on the information passed to them. So when the state changes in App.js it will update the lower components.
Check out: https://www.youtube.com/user/programmingwithmosh he is really good and as you mentioned is an issue before, he has great english and very in-depth.
Good luck and well done on using the lockdown for some education and self-betterment.

Related

Using SVG from assets folder into component in component folder not working

I'm new and still learning ReactJS, one issue that's stumping me is trying to use an SVG image I made in Vectornator from my assets folder to a header component in my component folder. It works fine when I made the mockup in HTML and I didn't had this issue when working on an Angular project last semester. Is there a fix or should I switch back to Angular and give up learning React lol. Also I'm using CRA since I just found out there's a lot of other ways to create a React app, chaos for a later date.
I don't know if it has any issue with folder structure because wherever I put the image it gives me this error.
Error Message
This is how my folder structure looks like
Folder Structure
And this is my code. I tried doing this through using an img tag and by making the SVG a react component but nothing works to display the image.
import DVLogo from "../assets/DVLogo.svg";
// import {ReactComponent as DVLogo} from "./assets/DVLogo.svg";
const Header = () => {
return (
<header className="header">
{/* <div>
<DVLogo />
</div> */}
<img src={DVLogo} alt="Logo"/>
<h2 className="header-name">DV</h2>
<nav>
<ul className="nav-links">
<li><a></a>Search</li>
<li><a></a>Collections</li>
<li><a></a>About</li>
<li><a></a>Decks</li>
</ul>
</nav>
<a className="login-btn"><button>Login</button></a>
</header>
);
};
export default Header;
Thanks in advance for any help.
When I use ../ instead of ./
Error #2 part 1
Error #2 part 2
You are not in the correct directory.
When you import your image you need to:
import MyLogo from "../assets/DVLogo.sv" // Note the 2 dots (..)
If you are using the following format:
<img src={DVLogo} alt="Logo"/> // WRONG
You can not pass only DVLogo but also need the src:
<img src={DVLogo.src} alt="Logo"/> // CORRECT
I think it's weird that I'm posting an answer to my own question but maybe it might help someone else or if I forget I can always come back to this.
But what I did was create a component returning the actual SVG code and change the syntax of them to match the JSX.
Examples:
stroke-width to strokeWidth
style="fill-rule: nonzero;" to style={{ fillRule: "nonzero"}}
vectornator:layerName="card" to vectornatorlayername="card"
Below is pics of both for a more in-depth look at the differences if anyone is interested. Thank you guys for helping. Not changing majors yet!
Original SVG file
New SVG component

&#039 "It' being rendered in React

I am making an API call to: https://opentdb.com/api.php?amount=10
and getting question and answer data and then rendering them
but instead of symbols, I am getting this &#039 " It'
rendering like this
export default function Question(props){
return (
<div className="Question-wrapper">
<div className="Question--question">{props.question}</div>
<div className="Question--options">
</div>
</div>
)
}
By default, React does not allow create tags from string variables because this is too dangerous. You could use dangerouslysetinnerhtml if it is rly necessary. Please read documentation by this link https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

Menu items get from json (created server side, Nextjs) don't appear in HTML source code

sorry if the title is not very clear.
I try to explain myself: my site is built with Next.js and retrieves data from Sanity Studio (CMS).
In Sanity the user can create menu items.
I have a menu in the footer component, one in the sidebar component and another one in the header component. The thing is, I can fetch sanity only in pages. So I created a function that, with each build, creates a JSON with all the information entered by the user.
Next, to have the menu items throughout the site, this JSON is imported into the "Layout" component and stored in a specific react context.
And everything works fine. But I noticed one thing: if I look in the source code of the page, the menu looks like this:
<nav>
<ul></ul>
</nav>
even though it is rendered perfectly in HTML.
I guess it is because I generate the JSON server side and when the page is created that information is not available.
Any ideas?
Thank you
EDIT: this is the Layout component where I imported the JSON file
import styles from '#styles/components/Layout.module.css';
import React from 'react';
//other imports...
//imported JSON
import globalData from '#client/global-manifest.json';
//this is the normalize function
import { normalizeNavigationFromRaw } from '#utils/normalizeNavigation';
//this is the navigation normalized
const navigationData = normalizeNavigationFromRaw(globalData?.navigation ?? {});
export default function Layout({ children }: { children: React.ReactElement }) {
// some functions for open/close modal ...
//context method to store navigation
const { setNavigation } = React.useContext<any>(GlobalSettingsContext);
//store navigation in context
React.useEffect(() => {
setNavigation(navigationData);
}, []);
return (
<>
<Head>
// some head code
</Head>
<main className={styles.container}>
<HeaderWrapper
toggleMenu={toggleMenu}
toggleContactPanel={toggleContactPanel}
/>
<SidebarMenu
isOpenMenu={isOpenMenu}
toggleMenu={toggleMenu}
ref={sideMenuRef}
/>
<ContactPanel
isOpenContact={isOpenContact}
toggleContactPanel={toggleContactPanel}
ref={panelRef}
/>
{children}
</main>
<Footer />
</>
);
}
the other components involved have only the navigation context imported from useContext and used. For example the footer:
import * as React from 'react';
//other imports...
import { GlobalSettingsContext } from '#contexts/GlobalSettings';
export default function Footer(): React.ReactElement {
const { navigation } = React.useContext(GlobalSettingsContext);
return (
<footer
className={
isSingleVehiclePage
? `${styles.footer} ${styles.morePadding}`
: styles.footer
}
>
<LayoutContainer>
<div className={styles.secondary}>
<div className={styles.social}>
{navigation.footerSocialIcon &&
navigation.footerSocialIcon.map((el: any, mainKey: number) => (
<Link key={mainKey} to={el.titleLink ?? ''}>
<span className={`icon-${el.iconClass ?? ''}`}></span>
</Link>
))}
</div>
</div>
</LayoutContainer>
</footer>
);
}
From the provided description i assume you are using getStaticProps. (although the it would be basically the same issue for getServerSideProps)
In order for data fetched to be pre-rendered in html, you need to pass it as props, returning it from getStaticProps.\
What you are doing is passing data to a react context, which is rendered after hydration takes place.
I advise you to review the basics of nextjs to understand what code is executed in the client and which is executed in the server, along with how pre-rendering works.
please check https://nextjs.org/docs/basic-features/pages

<Route > component alternative in nextjs

I have 3 components in nextjs and i want to achieve the below snippet in nextjs
<Route path="/" component={homePage} />
<Route path="/about" component={aboutPage} />
<Route path="/faq" component={faqPage} />
Q1. How can i do the same in nextjs without page refresh? (without react-router)
(Edit : some scholars are suggesting to read the docs but i have read it thoroughly and what i want is to pass a component along with the route)
Is this even possible in next js?
Q2: If i have url as /products?product_id=productid and on refresh if i want the url to be /products (basically i want to remove all params on refresh) What is the best practice to do this?
Thanks in advance
NextJS functions on a convention-based filesystem-based routing. You'd need to place your components in a directory structure that matches the routes you are wanting.
More details here:
https://nextjs.org/docs/routing/introduction
The Next.js docs don't really cover how to change away from <Route> components, however they have a lot of examples as code on how to do most things with Next.js. https://github.com/vercel/next.js/tree/canary/examples/layout-component
The below is what I used as an alternative to the component (there's no direct Next.js alternative).
_app.js
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
Any page:
import Layout from '../components/layout'
import Sidebar from '../components/sidebar'
export default function About() {
return (
<section>
<h2>Layout Example (About)</h2>
<p>
This example adds a property <code>getLayout</code> to your page,
allowing you to return a React component for the layout. This allows you
to define the layout on a per-page basis. Since we're returning a
function, we can have complex nested layouts if desired.
</p>
<p>
When navigating between pages, we want to persist page state (input
values, scroll position, etc) for a Single-Page Application (SPA)
experience.
</p>
<p>
This layout pattern will allow for state persistence because the React
component tree is persisted between page transitions. To preserve state,
we need to prevent the React component tree from being discarded between
page transitions.
</p>
<h3>Try It Out</h3>
<p>
To visualize this, try tying in the search input in the{' '}
<code>Sidebar</code> and then changing routes. You'll notice the input
state is persisted.
</p>
</section>
)
}
About.getLayout = function getLayout(page) {
return (
<Layout>
<Sidebar />
{page}
</Layout>
)
}
The main part for the layout that you want to wrap around the pages, components/layout.js:
import Head from 'next/head'
import styles from './layout.module.css'
export default function Layout({ children }) {
return (
<>
<Head>
<title>Layouts Example</title>
</Head>
<main className={styles.main}>{children}</main>
</>
)
}
What's happening is the _app.js wraps all pages inside the declared layout. Each page then defines what layout that page belongs to. The layout then accepts a page as the {children} prop object of which you can then render anywhere in your layout page.
Next uses filesystem based routing, your folder structure should look like
-- pages
-- index.js
-- about/index.js
-- faq/index.js
For the custom component part, make a component that's clickable, on click, use next builtin router to redirect
const router = useRouter();
router.push('/');

React Router - how to load product-specific API data into it's own page / URL?

This is my first time tackling this problem with React so please bear with me! I'd like to accomplish the following:
When a user clicks on a product, it loads that product's link containing it's specific information (image, description, etc.)
That URL would be something like 'myapp.com/product#/'
The API data is actually contained as a JSON in a local db.json file and has all the information for each product that I'd like to pull in. I'm using the Context API for managing the data.
Here's a live demo and the full project code.
This is what I have so far:
export default function MachineCard({ image, title }) {
return (
<>
<div className="col-lg-3">
<div className="card">
<Link to="/details"> <-- want this to link to product-specific page
<img className="img-fluid" src={image} alt={title} />
<div className="title">
<h2>{title}</h2>
</div>
</Link>
</div>
</div>
</>
);
}
Any idea how I can accomplish this?
Any help would be greatly appreciated!
In react router there is an option to /:id this way and it'll pick it up and render the right product or page. I have forked your demo and I have added the solution check it out and let me know if it helped.
https://codesandbox.io/s/nce-forked-nizd5?file=/src/components/MachineCard.js
Also check this react router document it will help you a lot. https://reactrouter.com/web/example/url-params

Categories