I'm testing Svelte and one of the things I'm trying to do is create a blog. I'm keeping it simple, all I want is to click in a link an open an article.
I only have three files:
home.svelte
blog.svelte
article.svelte
Home.svelte
<script>
import { Router, Route, Link } from "svelte-navigator";
import Blog from "./Blog.svelte";
import Article from "./Article.svelte";
</script>
<main>
<Router primary={false}>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="blog">Blog</Link>
</li>
</ul>
<Route path="/">
<h1>Welcome to my beautiful website!</h1>
</Route>
<Route path="blog" component={Blog} />
<Route path="blog/article/*" component={Article}/>
</Router>
</main>
Blog.svelte
<script>
import { Router, Route, Link } from "svelte-navigator";
const articles =
[
{id: 1, title: 'Sample title', description: 'Sample description' },
{id: 2, title: 'Sample title 2x', description: 'Sample description 2x' },
];
</script>
<h1>List of articles</h1>
<ul>
{#each articles as article}
<li>
<Link to="article/{article.id}">{article.title}</Link>
</li>
{/each}
</ul>
Article.svelte
<script>
export let title;
export let description;
</script>
<h1>{title}</h1>
<p>{description}</p>
My problems:
When opening the URL blog/article/1 it shows undefined in both title and description
The point 1. makes sense, since I'm not passing anywhere values to the article route, how do I do it?
It doesn't make sense to me that in the home.svelte I have to declare the route of article, I think it should be declared in the blog.svelte, however, if I do that, the article route is not loaded once I try to navigate to it.
I have tried to pass data as argument but doesn't seem to work:
<Link to="article/{article.id}" title={article.title}>{article.title}</Link>
From svelte-navigator documentation, the right way is one of:
<Route path="blog/:id" component="{Article}" />
<Route path="blog/:id" let:params>
<Article id="{params.id}" />
</Route>
You will the receive a props named id in your Article component. You'll have to get the title & description out of this id (through a basic import or a http fetch or something else).
I don't know your whole project but I highly recomand you to have a look at svelte-kit (routing & server extension of svelte that can generate static site if you need) which handles routing natively. You can then use mdsvex or svelte-markdown as a way to display markdown as html:
the first one is better if your articles are file based
the second one is better if your article are stored in a database.
Related
I have a Main page that contains 4 section ** #home, #collection, #products and #contact** and I have 2 different page for /cart and /login
Navbar Code is Here
`<nav>
<div className='wrap-nav'>
<NavLink href="" className='logo'>NILESTORE</NavLink>
<div className='wrap-ul'>
<ul className='nav-links' >
<li><NavLink to="#home">Home</NavLink></li>
<li><NavLink to="#collection">Collection</NavLink></li>
<li><NavLink to="#products">Products</NavLink></li>
<li><NavLink to="#contact">Contact</NavLink></li>
</ul>
<ul className='nav-items'>
<li><NavLink to="/cart" className='cart' data-item={data.cartItems.length}><BsBag /></NavLink></li>
<li><NavLink to="/login" className='login'>Login</NavLink></li>
</ul>
</div>
</div>
</nav>`
App.js code is here
import React from 'react'
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./App.css"
import Navbar from './components/Navbar'
import Cart from './pages/Cart';
import Main from './pages/Main';
function App() {
return (
<>
<Router>
<Navbar />
<Routes>
<Route path="/" element={<Main />} />
<Route path="/cart" element={<Cart />} />
</Routes>
</Router>
</>
)
}
export default App
SO when I am in main page that works fine and I can reach that section when clicking the section like when i click on products i can reach on #products
After that when I click on /cart and /login page I can reach on that page but myNavbar is same for all pages so when I click on Products, it doesn't work
I have tried all the possibilities on changing the NavLink like I have changed #products to /#products but also It doesn't work
Is there any solution for that
I think you can do one of these two:
First You can change your navbar and when you go to a page like a login page or cart page , your navbar doesn't show the other option till the user get back to the home page.
Second is that you pass a variable when you click on those (home, collection, products, and contact). you will say okay go to the home page if I am not at the home page then you will check the state and if there was one of these variables (home, collection, products, and contact) you can navigate to them by using js.
pathname: '/somewhere',
search: '?some=search-string',
hash: '#howdy',
state: {
[userDefined]: true
}
basically, this is what you find when you use location hook.
for more information check out the website
react-router-dom "#location"
To navigate to a particular section of a particular page, you might want to use a HashLink in your Navbar component.
Installation:
npm i react-router-hash-link
Import it as:
import { HashLink } from 'react-router-hash-link';
And use it as:
<li><HashLink to={"/page#id"}>Contacts</HashLink></li>
You can learn more about the same here
Hope this helps!
I'm designing a simple application using create-react-app and I've recently delved into the power of react-router. However, I'm having an issue with pages getting stuck trying to load, and I'm not sure why.
I've got a Navbar component, for which I'll condense the gist of what it is.
import React from 'react';
import { BrowserRouter as Router, Link, Switch, Route } from 'react-router-dom';
import BlogPost from '../Pages/BlogPost';
// Condensed because a lot of the detail is unnecessary and no-one likes blocks of unneeded code
class Navbar extends React.Component {
render() {
return (
<Router>
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
</Switch>
</Router>
);
}
}
function About() {
return <h2>The about page.</h2>;
}
export default Navbar;
BlogPost represents a component that is a page in itself. The code looks like this. Again, I'll abstract away from the stuff that's not relevant.
import React from 'react';
import Navbar from '../Components/Navbar';
// Other components on this page. None of them reference the navbar or contain a router of their own.
import BlogBox from '../Sections/BlogBox';
import CommentForm from '../Components/CommentForm';
import CommentBox from '../Sections/CommentBox';
class BlogPost extends React.Component {
getBlogPost(address) {
// Gets blog data (like the title, description, content, image, etc.) using 'fetch' from
// an API at 'address'. Abstracted away because this isn't relevant.
}
componentDidMount() {
console.log("Blog post mounted!");
this.getBlogPost("http://localhost:8080/api/blog/samplepost");
}
render() {
return (
<div className="blog-post">
<Navbar />
<BlogBox post={this.state ? this.state.post : ""}/>
<CommentForm />
<CommentBox comments={this.state ? this.state.comments: ""} />
</div>
);
}
}
export default BlogPost;
The homepage of my application is located at '/'. It's rendered in my index.js file, the code of which is below.
import React from 'react';
import ReactDOM from 'react-dom';
import BlogHome from './Pages/BlogHome';
import BlogPost from './Pages/BlogPost';
ReactDOM.render(
<BlogHome />,
document.getElementById('root')
);
The homepage renders fine, but when I go to navigate to /post, the application attempts to load the page indefinitely, and eventually times out, being unable to do so.
Notice how the BlogPost page component renders the Navbar component, which in turn has a path /post which renders the BlogPost object? I'm not sure if I'm able to change this. Could this be the reason why the /post path can't load?
What concerns me the most here is that I eventually would like to add additional pages which will not only contain this same Navbar, but for which their page links also exist in this Navbar. For example, if I add an About page, this page will not only contain the Navbar, but its link will also be present in this Navbar!
Is there a way I can keep such self-page links in the Navbar, without the recursive render loop occurring?
Issue
You are creating a cycle between rendering Navbar and BlogPost when the current path matches "/post`.
In other words BlogHome renders a Navar which renders a BlogPost which then renders another Navbar and another BlogPost ad nauseam.
Solution
Restructure your navbar and routes a bit to split them out
index.js
Since BlogHome sounds like a page it should be placed on its own route. Move Router here to wrap entire app. Render BlogHome path last as that matches all path prefixes, so it will render if no other route is matched above it by the Switch.
ReactDOM.render(
<Router>
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
<Route path="/" component={BlogHome} />
</Switch>
</Router>,
document.getElementById('root')
);
Navbar
Remove the router and routes, leave links only.
class Navbar extends React.Component {
render() {
return (
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
);
}
}
Now each page should be free to render a Navbar or not.
try to remove Navbar in your BlogPost component, because when the location changes it will switch component here
<Switch>
<Route path='/post' component={BlogPost} />
<Route path='/about'>
<About />
</Route>
</Switch>
and
<nav>
<div id="navigationlinks">
<ul id="navlinks-left">
<li className="nav-item"><Link to='/'>Home</Link></li>
<li className="nav-item"><Link to='/about'>About</Link></li>
</ul>
</div>
</nav>
will persisit.
I have a problem with routing to a specific part of another functional component in React.
I have declared Route in Main component and Link around the place where I want to redirect from... it looks like this...
The main function gets:
<Switch>
<Route exact path='/news/:eyof' component={News} />
<Route exact path='/news/:svetsko' component={News} />
<Route exact path='/news' component={News} />
</Switch>
And I defined in other functional component:
<div className="card">
<Link to="/news/:svetsko">
<div className="card-header">
<h3>Artistic gymnastics world championship</h3>
</div>
</Link>
</div>
So by clicking on this link, I need to get redirected to News page class "svetsko" so I can read about that news... All news are in containers in same page....
Try something like this in your component:
let { scrollToSection } = useParams();
svetskoRef = React.createRef();
useParams() allows you to access :svetsko. When the component loads, you can use scrollToSection to navigate between different parts of the page. The scrollRef is used to access the DOM element you want to scroll to.
window.scrollTo(0,scrollRef.offsetTop)
The markup would look something like this:
<div className="card" ref="svetskoRef">
<Link to="/news/:svetsko">
<div className="card-header">
<h3>Artistic gymnastics world championship</h3>
</div>
</Link>
</div>
You need only one route like
<Switch>
<Route exact path='/news' component={News} />
</Switch>
you can give link like
<Link to={{
pathname: '/news',
state: { news : yourNewsName } // you can pass svetsko here
}}>
<div className="card-header">
<h3>Artistic gymnastics world championship</h3>
</div>
</Link>
You can access this state in your News Page like
<div>{ props.location.state !== undefined ? props.location.state.news : '' }</div>
After getting your news type like eyof :
Step 1 :
you can create on functional component which takes argument as your
data and return your new post jsx with your data.
Step2 :
So,when you get your eyof in your page then you are going to call
this function and pass your data related to your eyof and that function
return your new post to your page.
Ok, I found one really good library as a solution, it's called react-scroll and it has an option to wrap link you need in earlier defined scroll link, and to wrap component you want it to link as a specific part of the page with Element with id you gave to scroll link as a parameter... Try it if you need it somehow.
I'm trying to implement a fairly standard blog app using Svelte, Svelte Routing and Firestore, but I think I'm misunderstanding a fundamental part of how props are passed between components.
I based my initial code on the excellent tutorial on Fireship.io - which worked as per the tutorial: https://fireship.io/lessons/svelte-v3-overview-firebase/
From there I've added Svelte Routing - https://github.com/EmilTholin/svelte-routing - and I'm attempting to add a view route.
Relevant part of App.svelte:
<Router url="{url}">
<Navbar user="{user}" />
<div>
<Route path="posts/:id" component="{Post}" />
<Route path="posts/add" component="{PostForm}" />
<Route path="posts" component="{Blog}" />
<Route path="/" component="{Home}" />
</div>
</Router>
In my Blog Component I use a component called PostTeaser, in which I pass a link to the post view page.
Blog Component:
<div class="posts">
{#each posts as post}
<PostTeaser post="{post}" />
{/each}
</div>
PostTeaser component:
<div class="post-teaser">
<h2 class="title is-3"><Link to="posts/{ post.id }" {post}>{ post.title }</Link></h2>
<div class="post-teaser-content">{ post.content }</div>
</div>
Here I get a warning in the browser:
<Link> was created with unknown prop 'post'
Although the teaser does appear on the screen with the correct information.
When I click through to the post, i.e. the Post Component, my data is undefined.
I am placing export let post; in the script tag of each of my components.
Should I be using a "store" for my data? At the moment I'm fetching my data in the BlogComponent and passing it down the line. It would seem that this is incorrect. Any help gratefully appreciated.
See here for fuller example: https://codesandbox.io/s/romantic-cannon-ri8lo
With svelte-routing, you don't pass props from the <Link> component, you pass them from the <Route> component implicitly. Where you have this...
<Route path="posts/:id" component="{Post}" />
...you're telling the router that if the URL matches the pattern /posts/:id, it should render the Post component, passing it an id prop that matches that part of the URL.
The Post component is responsible for fetching its data based on that. So in this case, you could move the posts array into a separate module, and change Post.svelte accordingly:
<script>
import posts from "./posts.js";
export let id;
$: post = posts.find(p => p.id == id);
</script>
<div class="post">
<h1>{ post.title }</h1>
<div class="post-content">{ post.content }</div>
</div>
(Note that props are stringified because they're derived from the href, so we need a == comparison rather than ===.)
Here's a working fork.
Simple example:
Parent Component
<script>
import PostTeaser from "./PostTeaser.svelte";
let post = {
first: 'First prop',
second: 'Second prop'
};
</script>
<PostTeaser {...post} />
Child Component
<script>
export let first;
export let second;
</script>
First prop: {first} <br>
Second prop: {second}
Code here: https://codesandbox.io/s/spread-props-using-svelte-y7xou
The project I am working on is kinda of sensitive, but here's what I have that I can show you all.
When I click on one of the s in my NavBar, it changes the URL, but it does not change the view to the proper component. Does anyone have any idea why? If there's a better way I can phrase this or improve the quality of my questin, let me know.
My render that I return
<NavBar />
<BrowserRouter>
<div>
<Switch>
<Route path="/propertytypes" component={PropertyTypes} />
<Route path="/entitytypes" component={EntityTypes} />
<Route path="/associationtypes" component={AssociationTypes} />
<Route path={Routes.ROOT} component={Test} />
</Switch>
</div>
</BrowserRouter>
My NavBar
import React, { Component } from "react";
import { Link } from "react-router-dom";
class NavBar extends Component {
render() {
return (
<div>
<ul>
<li>
<Link to="/propertytypes">Props!</Link>
</li>
<li>
<Link to="/entitytypes">Ent!</Link>
</li>
<li>
<Link to="/associationtypes">Ass!</Link>
</li>
</ul>
</div>
);
}
}
export default NavBar;
After clicking Props link
Besides what #Ukasyah noticed about disparity between the Router you are using (you say you are using BrowserRouter) and the screen captures with the URL you are getting (that points out you are using HashRouter), you must be getting a problem with the code you are showing up because the <Link> component in order to work must be contained inside the BrowserRouter. In your browser console it must be happening this error:
Warning: Failed context type: The context router is marked as
required in Link, but its value is undefined.
So to avoid the problem and links start to work, your render should be something like this:
<BrowserRouter>
<div>
<NavBar />
<Switch>
<Route path="/propertytypes" component={PropertyTypes} />
<Route path="/entitytypes" component={EntityTypes} />
<Route path="/associationtypes" component={AssociationTypes} />
<Route path={Routes.ROOT} component={Test} />
</Switch>
</div>
</BrowserRouter>
Note that I put the NavBar component inside the div because BrowserRouter only allows to have a single child.
I have been looking at different SO questions to solve this issue and none of them helped. My problem was using BrowserRouter in multiple different components. Same as here.
For me, the issue was that my entire app was wrapped with a <Router>, because that was how the boilerplate code was set up. Then I was copying snips from BrowserRouter docs, and did not remove the <BrowserRouter> wrapper around the code. Nested routers won't work properly.
The mistake I made was, I started with the setup from the documentation, which involves using:
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
Then I started splitting everything into separate layout files like this. So I initially copied the whole import between multiple files. At some point I was cleaning up the code and realized I only needed to import the Switch but I foolishly forgot to remove the BrowserRouter as, and I ended up with:
import { BrowserRouter as Switch } from "react-router-dom";
Which is obviously wrong since it mapped BrowserRouter to Switch, you can't have nested BrowserRouter 's and that's what introduced the issue in my case.