Props passed through <Link> shows up as undefined - react-router

I'm passing down props through react-router component but when received state comes up as undefined.
I have made sure the component receiving the props is wrapped in withRouter. Just to add I'm using react-table here.
{
Header: "Title",
id: "title",
col: "title",
accessor: ({ id, name }) => {
console.log(history "history"); // this returns an object as expected
return (
<Link
to={{
pathname: bookShowUrl(id),
state: {
prevPath: history.location.pathname
}
}}
>
{name}
</Link>
);
},
width: 300
},
How do I fix this so that component rendered on bookShowUrl(id) is able to access the prevPath props?

Related

Passing parameters to component in react through map React

I'm relatively new to React and Typescript.
I used a map function to create a list, li, in typescript. I tried passing a parameter to a function with info from the mapped object, but it doesn't seem to happen. it seems like the same argument is mapped to all the elements, like so:
state = {
groups: new Array<IGroups>(),
showGroup: false,
groupId: 0
};
showMembers(groupId: number) {
this.setState({ showGroup: true, groupId: groupId });
}
render() {
return (
<div>
<ul>
{this.state.groups.map(group => <li>{group.name} from {group.cityName} <button onClick={() => this.showMembers(group.groupId)}>For members</button></li>)}
{this.state.showGroup && <GroupMembers groupId={this.state.groupId}></GroupMembers>}
</ul>
</div>
)
}
the same "groupId" is being passed to the component every time.
what am I doing wrong?

How to define variables in Vue router to be used inside components?

I have a navbar on top and a <router-view> right below it (as seen in App.vue). I want the title inside the navbar to change depending on the route/view I am on. Since my views in the <router-view> do not contain the title itself, I need to define them somewhere. An example for the scenario could be when reaching the route /login, the title in the navbar changes to "Login".
How do I achieve this?
When searching for a solution, I came across a lot of page title questions. I am not talking about the document.title assignment, however, that could be a solution, but not a perfect one. What if I wanted the title to be something else than the document title..
App.vue:
<template>
<Menu :isActive="isMenuActive" />
<Navbar #toggle:hamburger="onHamburgerToggle($event)" />
<router-view />
</template>
Vue router allows you to attach any information you want to any route using Route Meta Fields
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
meta: { title: "FOO" }
}
]
})
You can access the information for currently active route in any component using $route variable
const child = Vue.component('child', {
template: `
<div>
Child component ("{{ $route.meta.title }}")
</div>
`
})
const router = new VueRouter({
mode: 'history',
routes: [
{
name: 'route1',
path: '/route1',
component: child,
meta: { title: 'Hello from route 1!'}
},
{
name: 'route2',
path: '/route2',
component: child,
meta: { title: 'Hello from route 2!'}
},
]
})
new Vue({
el: '#app',
router,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<router-link to="/route1">Route 1</router-link>
<router-link to="/route2">Route 2</router-link>
<h4> Current route: {{ $route.meta.title }} </h4>
<router-view></router-view>
</div>
Every component can access the $route object, so you could use that directly in your template. Or you can access that object in the script and do something with it.
Imagine your routes have the name property:
router/index.js
routes: [
{ path: '/', name: 'home', component: Home },
{ path: '/foo', name: 'foo', component: Foo },
{ path: '/bar', name: 'bar', component: Bar }
]
You could show that name in the template with no script necessary:
Navbar.vue
<template>
<div>Title: {{ $route.name }}</div>
</template>
(meta is also a good idea here as explained in #MichalLevý's answer.)
Or you could access the route object in the script and create a title however you want.
Navbar.vue (Composition API)
<template>
<div>Title: {{ title }}</div>
</template>
<script>
import { ref } from 'vue';
import { useRoute } from 'vue-router';
export default {
setup() {
const route = useRoute();
const title = ref('My title ' /* Do something with `route` */);
return { title }
}
}
</script>

How to properly handle a prop change with a LitElement component?

My scenario:
I have a web component created with LitElement which has an object property.
In order to initialise it, i am waiting for the element to get created:
<script>
document.addEventListener("DOMContentLoaded", () => {
const instance = document.querySelector("#myInstance");
instance.config = {
data: [
{ firstName: "John", lastName: "Doe", age: 32 },
{ firstName: "Jane", lastName: "Boe", age: 30 },
]
};
});
</script>
<my-component id="myInstance"></my-component>
Let's say that i am going to change this data prop from time to time.
I would like to check the value of the data once it is changed and then decide what i should do next. In order to do that, this is the code of my web component:
#customElement("my-component")
export class MyComponent extends LitElement {
#property({ type: Object }) data: Object;
protected updated(_changedProperties: Map<PropertyKey, unknown>): void {
console.log(_changedProperties);
}
render() {
return html`
<div>blabla</div>
`;
}
}
The problem is that _changedProperties map has data but it is still undefined.
What am i missing here?
changedProperties is a Map of all the property names that changed... e.g. you can use it to check what changed - if you want to access the actual value you can use the property directly.
it look like this
if (_changedProperties.has('myProperty')) {
// react to a myProperty change
console.log('The new value of myProperty is', this.myProperty);
}

props showing empty array - React Native

I'm learning React on my own. I have a couple of questions. I'm trying to fetch data to another component. I've tried to setState after mapping JSON data. But it was showing an error “setState is not a function”.
How can I setState after mapping JSON data?
// Fetching data and passing JSON values to TabBarMenu component
export default class App extends Component {
state = {
temp: [],
description: [],
time: []
};
_getFiveWeather = (lat, lng) => {
fetch(`http://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lng}&APPID=${API_KEY}`)
.then(response => response.json())
.then(json => json.list.map(function(item) {
return (
<TabBarMenu key={item.dt_txt} time={item.dt_txt} description={item.weather.description} />
);
})
}}
In TabBarMenu.js, I'm trying to pass the props (time, description) to the _FirstRoute. When I did console.log(this.props), it shows empty array.
How can I grab the props value from the constructor?
I really appreciate your help.
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { TabViewAnimated, TabBar, SceneMap } from 'react-native-tab-view';
export default class TabBarMenu extends Component {
constructor(props) {
super(props);
console.log(this.props) // showing empty array
this.state = {
index: 0,
routes: [
{ key: '1', title: 'Weather' },
{ key: '2', title: 'News' },
{ key: '3', title: 'Photos' },
],
};
}
_FirstRoute = this.props => (
<View style={styles.container}>
<Text style={styles.textStyle}>1</Text>
<Text style={styles.textStyle}>{this.props.description}</Text>
<Text style={styles.textStyle}>{this.props.time}</Text>
<Text style={styles.textStyle}>{this.props.temp}</Text>
</View>
)...
Your _getFiveWeather definition is essentially useless because after fetching data, you are not really doing anything with the mapped components. You just do the map operation and then that's it -- nothing else is happening.
That method that fetches data should be concerned only with that -- fetching data; it should have nothing to do with generating components. You should set the state with the new data after fetching it. Something like this.setState({ ... }) after successful fetching the info.
Then, in the render() method, you verify if there is anything to render. That is, if there is any weather information in your component state properties, you do some sort of mapping to dynamically create the components you need to render.
Nowhere did I see the render() method in your code, so I think you should focus on learning the basics. Start with render(). Don't try to do too many things at once.

Can't access nested JSON data in my Vue Component

Im trying to figure out why I can't seem to access the following piece of JSON data in my Vue Component.
My project is setup using Vue-cli with the Webpack template and is roughly setup as follows when I run into the problem.
Data JSON
This file contains several projects
projects: [
{
"slug": "page-url-slug",
"title": "Page title",
"image": {
"src": "/static/images/project-image.jpg",
"alt": "Alt text image"
}
}
]
Router
routes: [
{
path: '/work'
component: Work
},
{
path: '/work/:slug',
component: WorkItem,
props: (route) => ({
params: route.params
})
}
]
Component JS
export default {
props: [ 'params' ],
data () {
return {
project: {}
}
},
mounted () {
this.$http.get('/static/data.json')
.then((response) => {
let projects = response.data.projects
// Find data with same slug param
for (let i = 0; i < projects.length; i++) {
if (projects[i].slug === this.params.slug) {
this.project = projects[i]
return
}
}
// Else go back to parent route
this.$router.push('/work')
})
}
}
Component HTML
<template lang="html">
<div class="page">
<h1>{{ project.title }}</h1>
<img :src="project.image.src" alt="project.image.alt" />
</div>
</template>
When I try to access the project.image.src or the project.image.alt I keep getting the following error messages:
[Vue warn]: Error when rendering anonymous component at ...
Uncaught TypeError: Cannot read property 'src' of undefined
I am pretty new to Vuejs and I just can't seem to wrap my mind around the fact this happens.
You have to add null check as you are loading project asynchronously, like this:
<img :src="project && project.image && project.image.src" alt="project.image.alt" />
When this is being rendered, at that time project is not populated and it is still {}, which you set it in the beginning.