React prop value logs "undefined" - properties

I recreated a problem with a smaller piece of code. Basically I want to console log the value of components prop. But it keeps logging "undefined"
var Something = React.createClass({
propTypes:{
vouch: React.PropTypes.string
},
render: function() {
return (
<div>
<h1 onClick={this.props.onClick} vouch={this.props.vouch}>Click!</h1>
</div>
);
}
});
var List = React.createClass({
log: function() {
console.log(this.props.vouch);
},
render: function () {
return (
<Something onClick={this.log} vouch="test" />
);
}
});
ReactDOM.render(<List />, document.getElementById('react-app'));

Did you forgot to pass it with props: vouch?
<PeopleList vouch="test">
It seems you misunderstood that in your code:
<h1 text="Increment!" onClick={this.log} vouch="Test">Click!</h1>
you are actually passing "test" to h1 element which does not make sense.
Also you can make your props a requirement so you can see errors pop out in your console if you are not passing props correctly by:
propTypes:{
vouch: React.PropTypes.string.isRequired
},

Related

Vue 3 display fetch data v-for

So, I'm creating a Pokemon application and I would like to display the pokemon names using the api : https://pokeapi.co/api/v2/pokemon/.
I'm doing a fetch request on the api and then display the pokemon names in my template. I have 0 problem when I try to display only 1 pokemon but I have this error when I try to display all my pokemons using v-for.
Do you have any idea why I meet this error ?
<template>
<p class="dark:text-white"> {{pokemons[0].name}} </p> //working
<div v-for="(pokemon, index) in pokemons" :key="'poke'+index"> //not working...
{{ pokemon.name }}
</div>
</template>
<script>
const apiURL = "https://pokeapi.co/api/v2/pokemon/"
export default {
data(){
return{
nextURL:"",
pokemons: [],
};
},
created(){
this.fetchPokemons();
},
methods:{
fetchPokemons(){
fetch(apiURL)
.then( (resp) => {
if(resp.status === 200){
return resp.json();
}
})
.then( (data) => {
console.log(data.results)
// data.results.forEach(pokemon => {
// this.pokemons.push(pokemon)
// });
// this.nextURL = data.next;
this.pokemons = data.results;
console.log(this.pokemons);
})
.catch( (error) => {
console.log(error);
})
}
}
}
</script>
<style>
</style>
I've just pasted your code into a Code Pen and removed the working/not working comments and the code runs and shows the names.
Maybe the problem is in the parent component where this component is mounted, or the assignment of the :key attribute
try :key="'poke'+index.toString()", but I'm pretty sure js handels string integer concats quiet well.
Which version of vuejs do you use?
Edit from comments:
The parent component with the name PokemonListVue imported the posted component as PokemonListVue which resulted in a naming conflict. Renaming either one of those solves the issue.
In the error message posted, in line 3 it says at formatComponentName this is a good hint.

The object sent as prop is undefined while testing a Vue SFC with Jest

I want to test a Vue single file component which receives a prop as input. When I mock the prop, which is an object, I get an error that the object is undefined, The error comes from the HTML where the values of the object are used. If I make the prop to be a string for example (and I remove answer.value and :class="{'active': answer.selected}" from HTML), everything works fine.
Component:
<template>
<div class="answer-container" #click="setActiveAnswer()" :class="{'active': answer.selected}">
<div class="answer">
<p>{{answer.value}}</p>
</div>
</div>
</template>
<script>
export default {
name: 'Answer',
props: {
answer: Object,
},
methods: {
setActiveAnswer() {
this.$emit('selectedAnswer', this.answer);
}
}
}
</script>
Test file:
import { mount } from '#vue/test-utils'
import Answer from './../../src/components/Answer'
describe('Answer', () => {
it('should receive "answer" as prop', () => {
const answer = {
value: 'testAnswer',
selected: true
};
const wrapper = mount(Answer, {
propsData: {
answer: answer
}
});
expect(wrapper.props().answer.value).toBe('testAnswer');
})
})
The error I get is:
TypeError: Cannot read property 'selected' of undefined
Please advise what am I doing wrong. Thanks!
I managed to fix this by adding a v-if="answer" on <div class="answer-container" ..., which is quite strange (as this is not async data) since the code works fine when checking the application in the browser - the problem only appeared while unit testing the component. I suppose there is also a fix in a Jest/Unit testing way, something like declaring the prop after the component finished rendering/mounting...

Undefined variable - While api fetch | Axios | Props

My main component - Home
A really simple component, I pass the fetch variable to another component.
<template>
<Page actionBarHidden="true">
<ComponentA :api="api.somevariable"></ComponentA>
</Page>
</template>
<script>
import axios from "axios";
import ComponentA from "./ComponentA.vue";
export default {
data() {
return {
isLoading: false,
result: []
};
},
components: {
ComponentA,
},
created() {
this.loadData();
},
methods: {
async loadData() {
let self = this;
console.log("fetch");
self.isLoading = true;
const { data } = await Endpoints.get();
self.isLoading = false;
self.api = data;
console.log(data); // returns the data as intended
}
}
</script>
The componentA is also simple
<template>
<Label :text="somevariable"></Label>
</template>
<script>
export default {
data() {
return {
somevariable: 0
};
},
props: {
api: {
type: Number,
required: true
}
},
mounted() {
this.somevariable = this.api;
}
};
</script>
The error I am getting is [Vue warn]: Invalid prop: type check failed for prop "api". Expected Number with value NaN, got Undefined in the componentA, after some quoting and requoting of console.logs it actually picks up the value. I am not sure why is that, is my approach wrong? This frustrates me, can't figure it out for some hours already.
api isn't defined in the data for the first component, so it won't be reactive. That should be giving you a warning message in the console.
data () {
return {
api: null,
isLoading: false,
result: []
};
}
The second problem is that when the component first renders it won't yet have loaded api from the server. Using await won't help with this, rendering the template will happen before the asynchronous request has completed.
Given the way componentA is currently written it won't be able to cope with api being missing when it is first created. So you'll need to use a v-if to defer creation until that data is available:
<ComponentA v-if="api" :api="api.somevariable"></ComponentA>
Without the v-if check it'll just be passing the initial value of api, which in your original code is undefined. That is what caused the warning mentioned in the question.
When you talk about 'quoting and requoting of console.logs', I would assume that those changes are just triggering hot reloading, which could easily cause components to re-render with the new data. That wouldn't happen otherwise because of the lack of reactivity caused by api not being included in the original data.

Vue.js re-render static content

I'm new with Vue.js, and I notice some content re-render after changing any data that is not part of that content, here is an example:
https://jsfiddle.net/gustavompons/rtxqhyv2/1/
HTML
<div id="app">
<input v-model="foo1">
<div v-html="showFoo1()"></div>
<div v-html="showFoo2()"></div>
</div>
JS
new Vue({
el: '#app',
data: {
foo1: 'foo1',
foo2: 'foo2'
},
methods: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
})
So every time I type on the input, I get "this should NOT re-render on input" in the console, which I think it's not ok because there is no reason to execute that piece of code every time.
Is this the way Vue work or am I doing something wrong?
I'm using vue.js v2
The results of methods are not cached and will be executed every time the component is re-rendered. If you want caching and dependency tracking, use computed properties instead:
computed: {
showFoo1 () {
console.log('this is ok to execute on input')
return this.foo1
},
showFoo2 () {
console.log('this should NOT execute on input')
return this.foo2
}
}
And get rid of the () when accessing them.

Vue.js - Keep Alive Component - Error next Tick

Description
I'm trying to take advantage of the keep-alive functionality of vue-js 2.3 so my AJAX call is made only once.
Problem
The second time I try to open the popup component I get this error :
Error in nextTick: "TypeError: Cannot read property 'insert' of undefined"
TypeError: Cannot read property 'insert' of undefined
Steps
Click on the button to display the popup
Wait for one second
Close the popup
Click again on the button
https://jsfiddle.net/4fwphqhv/
Minimal reproduction example
<div id="app">
<button #click="showDialog = true">Show Component PopUp</button>
<keep-alive>
<popup v-if="showDialog" :show-dialog.sync="showDialog"></popup>
</keep-alive>
</div>
<template id="popup">
<el-dialog :visible.sync="show" #visible-change="updateShowDialog">{{asyncData}}</el-dialog>
</template>
Vue.component('popup', {
template: '#popup',
props : ['showDialog'],
data(){
return {
show: this.showDialog,
asyncData: "Loading please wait"
}
},
methods: {
updateShowDialog(isVisible) {
if (isVisible) return false;
this.$emit('update:showDialog', false )
}
},
created:function (){
const _this = this
setTimeout(() => _this.asyncData = 'Async Data was loaded' , 1000)
},
});
var vm = new Vue({
el: '#app',
data: {
showDialog: false,
},
});
Real code of the popup component
<template>
<el-dialog title="Order in progress" size="large" :visible.sync="show" #visible-change="updateShowLoadOrder"></el-dialog>
</template>
<script>
let popUpData;
export default {
name: '',
data () {
return {
ordersInProgress: [],
show: this.showLoadOrder
}
},
props: ['showLoadOrder'],
methods: {
updateShowLoadOrder (isVisible) {
if (isVisible) return false;
this.$emit('update:showLoadOrder', false)
}
},
created () {
const _this = this;
if (!popUpData) {
axios.get('api/mtm/apiGetOrdersInProgress').then((response) => {
_this.ordersInProgress = popUpData = response.data;
});
} else {
this.ordersInProgress = popUpData;
}
}
}
</script>
Ok. So your problem here is the wrong life-cycle hook.
If you change created to activated... it should work. It did for me in your JS fiddle.
activated:function (){
setTimeout(() => this.asyncData = 'Async Data was loaded' , 1000)
}
There are two other hooks, activated and deactivated. These are for keep-alive components, a topic that is outside the scope of this article. Suffice it to say that they allow you to detect when a component that is wrapped in a tag is toggled on or off. You might use them to fetch data for your component or handle state changes, effectively behaving as created and beforeDestroy without the need to do a full component rebuild.
SOURCE: here