How to pass props between routes in vue.js? - javascript

I want to send a variable as a prop from a route to another in vue.
I have a vue component, Champions, using a v-for and creating a new component called ChampionCard for each character in a JSON file, and binding the current champion each time.
In ChampionCard, I just show the name and image of the champion.
I want that, when clicking on a ChampionCard, you get redirected to another component called Champion with URL champions/:champion.
But I can't find a way to send the champion data between those 2 routes.
The Champions component :
<div class="champions">
<ChampionCard v-bind:champion="champion" v-for="champion in champions" :key="champion.key">
</ChampionCard>
</div>
The ChampionCard component :
<article #click="redirectTo(champion)" class="champion">
<img class="champion-icon" :src="champion.image" :alt="champion.name">
<h2 class="champion-name"> {{ champion.name }} </h2>
</article>
redirectTo(champion) {
this.$router.push({ name: 'champion', params: { champion: champion.key }})
}
The above code is working as I get redirected to champions/championName, but I don't have access to my champion variable. What would be the best way to send it as a prop in Champion component ?
Thanks :)

My alternative is: While redirecting to champions/:champion route, just send the id of the champion (such as champions/123).
When you are redirecting to this route, you can store champion object in a global place (say store). So that you can lookup with id (123) when you're mounting the route.
One step further, if you cannot find the object in the global store, you can initiate a remote call. So that your route will not be broken if 123 is not in the store. (User can go directly to that route if they save some bookmarks of that page etc.)
To keep your object in the global place, you have different alternatives:
Simple State Management (Simple/Basic implementation)
Using Vuex

I think you can achieve what you want doing something like this:
Declare a new route:
{
path: '/champion/:championKey',
name: 'Some name',
component: ChampionComponent,
}
Then, when redirecting to this new route:
redirectTo(champion) {
this.$router.push("/champion/" + champion.key)
}
Now you can access to the url param like this:
this.$route.params.championKey // as declared in router.js

Related

how to use data that are sent by this.props.history?

When I want to go from a route to another with this.props.history.push("/"), also I want to send some additional data, for example: this.props.history.push('/postDetail', {data: item}). But I do not know how where to define this data in the class where we went.
Thank you in advance
You can send a prop called state that comes from the router:
this.props.history.push({
pathname: '/postDetail',
state: { data: item }
});
So now your component attached with that route will have the location prop available, inside the location object lies the state that you have passed.
More info here: https://reacttraining.com/react-router/web/api/history

How can I pass the value from my function to another component in another file

I'm making a react application that shows details about the pokemon you searched. So I have a Home component which has an input field + submit button.
I want to render my api call in my Main component.
The question that I have is : How can I pass the value from this input field that is located in my home component to my main component when I enter submit?
home component details
I need this value to update my pokemon name state in my Main component in order to get the pokemon name for my fetch call.
I need this value to be stored inside my 'searchValue' state.
Main component details
any tips?
One of the ways you can achieve this by Using ref in reactjs , Inside your Main Component you need to make a reference, like :
componentDidMount() {
this.props.onRef(this);
}
// Delete the reference once component is unmounted
componentWillUnmount() {
this.props.onRef(undefined);
}
And then create a method , which will receive the values from a the Home component and then setState like :
method(values) {
this.setState({ searchValue: values });
}
Now inside your Home component you need to reference method component before your input like , (You can amend it accordignly)
import Home from './Home'
<Home onRef={ref => (this.home = ref)} />
<Form onSubmit={e => { this.onSubmit(e) }}
Make sure to add onSubmit method inside main component which will send the values to Home Component
onSubmit = values => {
this.home.method(values);
}
You can read more about Ref and the DOM on React Documentation
I would propose you to take a look at redux which is great tool for state management. Redux will ensure you have a single source of truth.
What you will have to do is create an Action which would dispatch an event to update the state, a Reducer which would update the state (value of the search-key in redux-store). Your Main component will read the data from the API (Same Action-Reducer way) & render it without having to bother about the current state. I can explain the whole architecture in detail if you are more interested. This architecture will have less bugs & clear flow of information including shared state between components.
I know this sounds bit too complex but its worth a try if your application is growing.
Few suggestions:
Your Main component has too much of logic. Components should have least logic as possible so they are more deterministic. Please also read about React Stateless functional components
Here are some links if you wish to take redux path
10-tips-for-better-redux-architecture
Redux Best Practices

Vue.js, pass data to component on another route

Simple task to pass data from one page to another made a real headache to newbie in Vue.js
Here is my router
I'm rendering a form on "/" page, which make an API request,
and I just want to pass data to another route page with another component
Is it so hard to do in Vue? It made a real headache for me today.
Get data from API, save & send to another component. How can I do it?
As Antony said, since you've already enabled props in router/index.js, you can pass parameters in router.push like this:
router.push({
name: 'events',
params: {
items: data
}
});
then you will be able to receive items as props in EventsDisplay.vue
export default {
name: 'eventsDisplay',
props: ['items'],
};
If you want to save it globally, you could use an event bus or a VueX store to contain it, then save and load it from this event bus or store when you need to access it.
If you want to pass it between those two components only, and only when accessing the second page from the first one, you can pass properties to the route argument as per this guide: https://router.vuejs.org/en/essentials/passing-props.html
Try using Vuex
In Source Component
this.$store.commit('changeDataState', this.$data);
this.$router.push({name: 'user-post-create'});
In Destination Component
created () {
console.log('state', this.$store);
this.$store.getters.Data;
}
Add props true in your vue router
{
path: "/pay-now",
name: "pay",
props: true,
component: () =>
import(/* webpackChunkName: "about" */ "../components/account/pay.vue"),
beforeEnter: AuthGuard,
},
After that pass props with router like that
this.$router.push({
name: "pay",
params: {
result:this.result,
}
});

Inject reducer for on demand component which was not in the store or combined reducers initially

I'm trying to build some modular SAP so many teams can work separatelly.
Basically, I want my containers to be independent in terms of container, store, reducers, sagas.
The actual question is (example code):
I render a basic template:
<div>
<a onClick={emitLoadUserListAction}>Load user list</a>
<UserList/>
</div>
At this point, I make use of 1 reducer for UserList to keep the array of users (empty at the beginning).
Let's assume I have a saga, waiting for this data to come as a user list in a json.
Store:
{
UserList: []
}
Once the saga fetches the data, publishes an action modifiying the current store:
Store:
{
UserList: [{name:"john",counter:0},{name:"pepe",counter:0}]
}
Now my UserList component can list this as we have the mapStateToProps pointing to this part of the store.
this.props.userList.map ( (userData,i) => { return <User data={userData}> } ))
So now everything is working like a charm if User component is just a normal component.
But what if User is actually a container, which is expecting to work on its own, with its own state I didn't connected yet via its own reducer. I don't want his parent to manage it. I want user to be independent as I could pass its location in the store with reselect selector or similar, or I could just pass the index in the array as a prop, so I could be the selector. This way I would have store injected in props, but I won't have reducer.
I'm pretty sure many of you already pass through this but I couldn't find a proper answer.
As you can see the idea is to have a component, which is loading on demand, not in the initial combineReducers, not handled by its parents, just render, and reducer injected to work on its own.
If I could have just a way to load its reducer on demand then, I would not store the data in the UserList but it will be a composition of reducers.
Thanks a lot in advance.
I'm continuing on from my comment and the question that followed so I can expand on it without the restrictions of the comments section.
Yes, my library calls replaceReducer on the store to in order to, well, replace the reducer with the new one included. In order to do so, I provide a Higher-Order Component (HOC) which bundles the component with it's associated reducer and performs the replacement when it is mounted.
The interface looks something like this:
export const MyBundledComponent = bundle(MyComponent, myReducer)
The only requirement for it to work is that the component is mounted within a Provider from react-redux. This gives the HOC access to the store on React's context the same way the connect HOC does. This isn't really a very prohibitive restriction though, as most redux apps have a Provider at the top of the tree already.
Hope this helps.
So far I found resources like this:
https://medium.com/#jimmy_shen/inject-reducer-arbitrarily-rather-than-top-level-for-redux-store-to-replace-reducer-fdc1060a6a7
which allow you to inject reducers on demand by replacing the main reducer by using the Redux store API store.replaceReducer(nextReducer)
The problem with this solution is the need to have access to the main store object from the child component that should be encapsulated.
For the moment working not ideal solution that I found is to deliver the encapsulated component with a "multiple components reducers" meaning that the reducer assumes there could be more than one component under the same parent where each one has different ids.
So each action should check the payload ID, in order to get the state from the store object.
This would mean a small change in the hierarchy as the component would not be child but sibling.
Following the previous example, imagine that we list a shallow version of the user list and then you show more data once u click on any user:
`
Store: {
UserList: [], // basic info, id plus minimal data
users: {} --> userReducer // listing each user by key
}
`
This way the user component will expose multiUserReducer instead of logic for just one.
This obviously means the reducer is loaded in advance, even if you never load any user componet.

How can you pass data from a parent route to a child route in Vue.js nested routes?

I am trying to use nested routing in my Vue.js application. I have the routing working, however I cannot figure out how to pass data from a parent route down to a child route.
Basically, the parent route is going to retrieve an object that has properties. For each specific nested child route, I want to show one of the properties on that object.
For example, if I have the object below:
myDataObject : {name : "Foo" , profile : "Profile Data", posts : "Posts Data" }
I would like to pass the "profile" variable to the child route "/user/:id/profile". In the case of "/user/:id/posts", I would like to pass the "post" variable in.
I thought I could accomplish this using props, but I cannot find an example that fits with routing and what I tried does not seem to work.
Here is a link to a jsfiddle of what I am trying to do.
http://jsfiddle.net/90q4sucj/2/
This is definitely doable with props.
In parent component
<template>
...
<router-view :profile="myDataObject.profile" />
...
</template>
In child component
<script>
export default {
name: "child",
props: ["profile"]
...
Now, in your child component you may access the data by referring to this.$props.profile.
I am using this pattern with Vue 2.5.16. and Vue Router 3.0.1.
PS: A good option is to also use vuex for such scenarios.
See the answer below for the correct answer
! You can retrieve data by using services you create. In the example given I've updated to follow the "fetch data after navigation" sample shown in the docs. It has a userService that will handle getting the user's profile.
! const userService = {
findProfile(id) { return 'Profile Data'; }
};
! Then I updated the UserProfile component to get the profile when it's created and it watches the $route for changes.
! const UserProfile = {
data() { return { profile: null } },
template: 'Profile {{ $route.params.id }} {{ profile }}',
methods: {
setProfile: function () { this.profile = userService.findProfile(this.$route.params.id); }
},
created: function () { this.setProfile(); },
watch: { '$route': 'setProfile' }
}
! As for passing it through like props: [] I didn't see a way but that's probably a good thing because it could start getting pretty convoluted. Here you know explicitly where the user profile is coming from and don't need to follow a rabbit hole to figure it out.
! http://jsfiddle.net/90q4sucj/3/

Categories