How to get full path with React Router - react-router

I'm using React Router 4. I would like to know how to get the full current path in a matched component, not just the base path.
I know that React Router inject a history and location objects in the props of the rendered component. I've realized that I could either do
props.history.createHref(props.location)
or build the path manually with
props.location.pathname + props.location.search + props.location.hash
Are there better ways to do this?

Related

Why are the react-router component props not including history?

I'm loving v4 but in 4.1.2 this keeps tripping me up when using the browser router:
With a component in a Route component I have these props passed in: {computedMatch, location, path} although the documentation tells me to expect {match, location, history} which is what I get with the hash router.
To get the history passed in I have to use the withRouter wrapper which feels very clunky because the relevant component is the component prop to a Route component.
The documentation sounds right to me. Is this a bug?
You can get access to {match, location, history} if you use Route as
<Route path="/" component={myComponent}
In above code you will have match location and history accessible inside myComponent.
Or else you have to use withRouter

Vue/Vuex - Load state from JSON file

I am trying to bulid a simple app using Vue / Vuex starting from vue-cli webpack template.
The app works fine but I would like to add the possibility to load and save the state in a JSON file.
Is there a best practice in order to do that ?
My first idea was to read the data into the file store.js
import Vue from 'vue'
import Vuex from 'vuex'
import fs from 'fs'
// Read file
let loaded = null
fs.readFile('./data.json', 'utf8', (err, data) => {
if (err) throw err;
loaded = data;
})
Vue.use(Vuex)
const state = {
notes: loaded,
activeNote: {}
}
...
...
But I am getting error when I try to import fs module.
There are great plugins available for exactly what you're trying to do.
Basically, having Vuex and defining a state is he way to go, however, you should do it a little different.
Take a look at this plugin:
https://github.com/robinvdvleuten/vuex-persistedstate
Since you're using Webpack it is pretty easy to install, use yarn add vuex-persistedstate for example..
Then, you import the plugin using import createPersistedState from 'vuex-persistedState'.
Now you change up your store a little bit, doing something like this:
export const store = new Vuex.Store({
state: {
yourVar: 0
},
mutations: {
changeValue (state, number) {
state.yourVar += number
}
},
plugins: [createPersistedState()]
})
That's basically it. All you need to do is add the plugin line to your Vuex store and all variable data inside your state will be saved in the browsers localStorage by default. Of course, you can read through the GitHub repository to see how you can use sessions, cookies etc, but that should work just fine.
The important part here are your mutations, since everything you want to do with your store variables HAVE to be declared by a mutation function.
If you try to modify your stored variables using ordinary functions, you'll get some warnings. The reason behind this is to ensure that no unexpected mutation of your data will take place, so you have to explicitly define what you want your program to accept in order to change your variables.
Also, using the export const store before your new Vuex.Store allows you to import that state in any of your Vue components and call the mutation functions out of there as well, using store.commit('changeValue', number).
I hope this answer helps you out a little bit, I was struggling with the exact same problem about 2 days ago and this is working like a charm ;)

React router listen get params

I am creating a blog using React/React-Router/Redux, and depending on the location, I want to show different blog posts, so if you are on /category/cat1 you don't have the same list of blogs than if you are on /category/cat2.
So I'm thinking on storing the blog list in the store and my react component would pick it up from there so I could just have actions updating my state.
My thinking is listening on the browserHistory so I can get when the location changes and trigger the action which would update the new blog list, but I can't find how to get the params from my location path like I would from my component props /category/:catName
How can I get those params?
Is it actually the way to do it or should I use a different approach?
Thanks.
From the version 2.0.0 upgrade guide:
RoutingContext -> Router render prop
You can now pass a render prop to Router for it to use for rendering.
This allows you to create "middleware components" that participate in
routing. Its critical for integrations with libraries like Relay,
Redux, Resolver, Transmit, Async Props, etc.
The default is basically this:
<Router render={props => <RouterContext {...props} />} />
This render prop on the Router is a hook into the render stage, and those props that are passed to the function contain the parsed route params, as well as lots of other routing context. Just make sure your function returns a RouterContext, or some equivalent, in the end.

Globally-available mixin in VueJS

I'm trying to create a mixin that's globally available, but not automatically injected into every component. i.e. i do NOT want this: Vue.mixin({...});
I set up the project according to these instructions. This is my project structure. I also have assets/js/mixins.js file in there containing my mixins.
I would like to be able to do this in my individual .vue files (many of my components use myMixin but not all of them):
<script>
export default {
mixins:[myMixin],
data:{....}
}
</script>
<template>
<!-- some template code -->
</template>
So far the only way to do that is to add this line to the top of every component that needs it:
import {myMixin} from './assets/js/mixins.js"
but is there a way to do this once and have myMixin variable available globally? I've tried including it in main.js and in app.vue but I still get "myMixin is not defined" error if I try to use myMixin in any of the child components.
Or is there another way to register a mixin that doesn't require me typing the path to the mixins.js file in each component?
I would suggest setting your mixin up as a plugin. To do that, wrap it within an function call install and export the install function. Then, wherever your instantiate your app, you can simply do Vue.use(yourMixin):
Docs:
https://vuejs.org/guide/plugins.html
http://vuejs.org/api/#Vue-mixin
Example:
//- build your mixin
const mixin = {
// do something
}
//- export it as a plugin
export default {
install (Vue, options) {
Vue.mixin(mixin)
}
}
//- make it globally available
import myMixin from './myMixin'
Vue.use(myMixin)
Vue.use calls in the install fn(), so all subsequent Vues (or all if none have yet been created) have the mixin functionality
Careful of namespace clashes on globally available mixins (!)
A couple of ideas:
In main.js you can declare window.myMixin = {...}, which I believe will make it available in any component loaded after that.
edit: this is even better if you use this.myMixin, as this will refer to the global scope. That way you aren't depending on window existing, so it could be used in more environments
To not have to declare the full path in each file, you could create the mixin as a local NPM module as per Installing a local module using npm?. Then you could just import myMixin from 'myMixin'. This would be the more proper way to do it I think, that way you're still loading dependencies in each component, just with some shorthand.
Here is the correct way to register a mixin globally in app.js
Vue.mixin(myMixin);

Navigation outside of component in react-router

Is this outdated? https://github.com/rackt/react-router/blob/95094769caca201b8e9afe68ff3d6cb4ff280fac/docs/advanced/NavigatingOutsideOfComponents.md
I can't seem to get it working.
I'm exporting the history object like this:
export const history = require('history/lib/createBrowserHistory')();
And then I'm using it like so:
history.push('/home');
But the page doesn't change, only the URL changes.
This functionality still works fine and the current docs still have it in master
Notice the extra () at the end of the require in your code. That's a function call which returns a new history object instance.
In that doc they do the function call once in history.js and export the instance. They then require history.js and used that instance for both the router and outside of the router.