-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Questions about state between nested components #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
In my opinion, the user's logged-in status and key are not UI state and therefore belong outside of your component hierarchy. So, for example, in my own project, I have an "auth" module that contains the session info and exposes functions like logIn, logOut, etc. (For notifying various parts of the UI when the login status changes, I expose a rxjs Observable.) Depending on the complexity of your app, you could also consider using something like Flux or Redux to manage your application state. Anyway, that's just my two cents... Hope it helps. |
As a general rule (for all component-based architectures, not just Svelte), a piece of state should be stored at the highest component in the tree that's a common ancestor of all components that need to use it, which in this case would be One option would be to handle routing differently: {{#if route === '/login'}}
<Login user='{{user}}'/>
{{elseif route === '/about'}}
<About/>
{{...and so on}} It starts to look a bit messy when you have a lot of routes, but it works and is fairly self-explanatory for the next developer. Handling the state outside the component tree as @therealnicksaunders is also a fine idea (in a way, something like Redux is taking the 'highest component in the tree' mantra to its logical conclusion by putting all data above all components – personally I don't tend to distinguish between UI state and non-UI state, and I like having component-local data, but there's no wrong answer here), it's just a case of adding a bit of subscription boilerplate to |
Thanks for the replies. I would like to avoid using too many external libraries so I'll try @Rich-Harris's approach first and if I fail I'll resort to something like redux or mobx (since I heard about them and I never used rxjs). If I use something like this {{#if route === '/login'}}
<Login user='{{user}}'/> does it mean it's replacing my router code? const router = createRouter({
'/': Home,
'/home': Home,
'/login': Login,
'/doctors': Doctors,
'/about/:name': About,
}); If anyone got the time, can you show the needed code (gist, modify my code, new sample app, etc). |
I think It's working now! - https://github.com/oren/svelte-router-example/blob/9799b6736f1a670286daa34df4cefffdee49d86f/src/App.html let me know if that's what you meant. I used a helper function: helpers: {
route () {
return window.location.pathname;
}
} |
Why not use just the url <!-- Router.html -->
<main ref:router></main>
<script>
export default {
onrender() {
let component = null
change = change.bind(this)
window.addEventListener('hashchange', change)
if (this.to()) change()
else this.to('home')
function change() {
const auth = this.get('auth')
const to = this.to() || 'home'
if (auth && auth() === false) {
if (to !== 'signin') return this.to('signin')
}
document.querySelector('html').scrollTop = 0
document.querySelector('body').scrollTop = 0
if (component) {
component.teardown()
if (component.onleave) component.onleave(to)
}
const Component = this.get('routes')[to]
component = new Component({
target: this.refs.router
})
if (component.onenter) component.onenter(to)
}
},
methods: {
to(to) {
if (to) window.location.hash = to
return location.hash.slice(1)
}
}
}
</script> And then something like this: <!-- App.html -->
<Router routes="{{routes}}" auth="{{auth}}" />
<script>
import Home from './Home.html'
import Signin from './Signin.html'
import Router from './Router.html'
import store from '../store'
import { getIsAuthenticated } from '../selectors'
export default {
data() {
return {
routes: {
'home': Home,
'signin': Signin
},
auth(to) {
const state = store.getState()
const isAuthenticated = getIsAuthenticated(state)
if (!isAuthenticated) return false
}
}
},
components: {
Router
}
}
</script> |
BTW. Also notice the and the other thing is that you can have a global helper like this for jumping between routes. export function transitionTo(to) {
window.location.hash = to
} Its not perfecto but it does its job for a small application without dependencies like mine. This was inspired by this https://gist.github.com/FWeinb/11e72e8bdfedfb38b40836c9b7f565b9 |
I'm just going to toss this out there as another alternative... I searched high and low for an existing client-side routing solution that played nicely with Svelte, had a familiar API, and would allow me to modularize my routing configuration (since I prefer to package by feature). Since I couldn't find anything that seemed to fit the bill, I spun up my own routing library, an example of which you can view at https://github.com/sawbladejs/example. Using this routing library, you should be able to do something like this in order to communicate between your App and Login components (untested):
Anyway, it does introduce a runtime dependency (not as cool as Svelte that way), but I think it scales better than a basic routing implementation using switches (which was the first approach I tried, by the way!). |
Will close this as it looks like the issue was resolved |
I have App.html and a child component - Login.html.
When the user submit the login form the Login component calls the server endpoint and on success I change
user.loggedIn
to true and add a user key to the localStorage. The problem is the App.html should be aware of it so it can change it's content and remove some UI elements (link to login for example).Here is my example repo:
https://github.com/oren/svelte-router-example/blob/c638c8786084a327bffdcac99da13b55695667cb/src/components/Login.html
Thanks!
The text was updated successfully, but these errors were encountered: