react-router this is undefined - javascript

Uncaught TypeError: Cannot read property 'dispatch' of undefined
This occurs in ReactRouter.js in handleLocationChange:
handleLocationChange: function handleLocationChange(change) {
this.dispatch(change.path, change.type);
},
This is downstream from my call to
this.context.transitionTo('something');
where 'something' is one of my defined routes. Why would 'this' be undefined?
Here is my component calling the code:
var React = require("react");
var Router = require("react-router");
var { Link } = Router;
var Button = require('core-ui').Button;
var AppointmentsHeader = React.createClass({
mixins: [React.addons.PureRenderMixin],
contextTypes: {
router: React.PropTypes.func
},
render: function () {
console.log("AppointmentsHeader:render");
var router = this.context.router;
// default to hidden
var displayClassInline = "appointments-hide"; // hide/show this element if the current page is Landing Page
if (this.props.currentState.get('currentState') === "landingPage")
{
displayClassInline = "appointments-block-show";
}
return (
<div className={"appointments-header cv-grid " + displayClassInline}>
<div className="appointments-title">Appointments</div>
<Button label="Create Appointment Event" style="primary" onClick={this._onClick}/>
</div>
);
},
_onClick: function() {
console.log("AppointmentsHeader 'Create Appointment Event' button clicked");
var newStatus = this.props.currentState.set('currentState', "CreateAppointment");
this.props.handleChange(newStatus);
this.context.transitionTo('createAppointmentsEvent');
}
});
module.exports = AppointmentsHeader;

This line:
this.context.transitionTo('createAppointmentsEvent')
Should be:
this.context.router.transitionTo('createAppointmentsEvent');
or
this.transitionTo('createAppointementsEvent')
You are accessing the singleton router two different ways in your example:
The Navigation mixin
The Router that is injected via the contextTypes hash
The API Is very confusing right now because Ryan went down one road (getting rid of mixins entirely) and then decided to "undepricate" the mixins.

Related

Error in running unit test for Vue webapp

I am writing a webapp with VueJs, I am trying to setup unit test for it, I got inspired from vue-mdl unit-tests. But the tests are not running properly for my code and I am getting vm.$el as undefined, so not able to move forward at all.
Here is the component, I am trying to test:
Confirmation.vue
<template>
<div>
Your order has been confirmed with the following details.
</div>
</template>
<script type="text/javascript">
export default {
data () {
return {
data_from_pg: null
}
}
}
</script>
and here is test for it, which fails
Confirmation.spec.js
import Confirmation from 'src/components/Confirmation'
import { vueTest } from '../../utils'
describe('Confirmation', () => {
let vm
let confirmation
before(() => {
vm = vueTest(Confirmation)
console.log('vm.$el ' + vm.$el) => this prints undefined
confirmation = vm.$el.querySelector('#confirmation') => so this line gives error
// confirmation = vm.$('#confirmation')
})
it('exists', () => {
confirmation.should.exist
confirmation.should.be.visible
})
})
utils.js
export function vueTest (Component) {
const Class = Vue.extend(Component)
Class.prototype.$ = function (selector) {
return this.$el.querySelector(selector)
}
Class.prototype.nextTick = function () {
return new Promise((resolve) => {
this.$nextTick(resolve)
})
}
const vm = new Class({
replace: false,
el: 'body'
})
return vm
}
My complete code is available here, with all the test config, which I have tried to change many times, but could not figure out how to make it work. Please let me know if you see some error somewhere.
The vueTest function in utils is trying to load the Vue instance into the body tag:
const vm = new Class({
replace: false,
el: 'body'
})
return vm
The unit tests do not load index.html as an entry point into the app, but rather the individual components that you want to test; Therefore, you do not have access to document or html elements and the component is never mounted. I'd suggest using vm.$mount():
If elementOrSelector argument is not provided, the template will be rendered as an off-document element.
You could change the above lines to something like the following
const vm = new Class();
vm.$mount();
return vm;
Your tests should now have access to the $el property.

Why am I unable to access my Mongo collection in a React component?

Using reactjs:react as the official react package isn't installing correctly for Windows yet.
Just trying to get to grips with React and getting pretty frustrated by what seem to be small things. For some reason I can't actually query any of my Mongo collections via my React components - the basic Mongo queries in the Chrome console work as expected...
var ExampleComponent = ReactMeteor.createClass({
getInitialState: function() {
return {data: []};
},
//didn't think the following was necessary, but tried it to no avail:
startMeteorSubscriptions: function() {
Meteor.subscribe('exampleCollection');
},
componentDidMount: function() {
var collection = ExampleCollection.find().fetch();
console.log(collection); //Empty Array []
console.log(ExampleCollection); //Mongo Collection
console.log(ExampleCollection.find()); //Cursor
console.log(ExampleCollection.find().fetch()); //[]?? wtf?
this.setState({data: collection});
},
render: function() {
return (
<div data={this.state.data}>
Hello World?
</div>
);
}
});
Meteor.startup(function() {
React.render(<ExampleComponent />, document.getElementById('root'));
})
So what's going on here? Any help would be appreciated, I'm not finding as many resources about doing the basics with React and Meteor that I had hoped.
In reactjs:react, you need to implement a method: getMeteorState()
This is what sets your data to be available in your component when render() is called. You still should implement startMeteorSubscriptions if you're doing pub/sub with your data (which you did correctly).
For example:
var ExampleComponent = ReactMeteor.createClass({
// Methods specific to ReactMeteor
startMeteorSubscriptions: function() {
Meteor.subscribe('exampleCollection');
},
getMeteorState: function() {
return {
data: ExampleCollection.find().fetch()
};
},
// React Methods
getInitialState: function() {
return {};
},
render: function() {
var data = this.state.data;
return (
<div>
{/* Present your data here */}
</div>
);
}
});

Uncaught TypeError: Cannot read property 'toUpperCase' of undefined react state item

I'm new to React and Javascript and I'm trying to render the following React component:
'use strict';
var React = require('react');
import ToReadList from './toreadlist.js';
var ToRead = React.createClass({
getInitialState: function() {
return { bookTitles: [] };
},
handleSubmit: function(e) {
e.preventDefault();
this.state.bookTitles.push(React.findDOMNode(this.refs.bookTitleInput).value.trim());
this.setState({items: this.state.bookTitles});
},
render: function() {
return (<div>
<form onSubmit={this.handleSubmit}><input type="text" ref="bookTitleInput"></input>
<input type="submit"></input></form>
<ToReadList bookTitles={this.state.bookTitles} />
</div>
);
}
});
module.exports = ToRead;
But I am having the following error on my console: "Uncaught TypeError: Cannot read property 'toUpperCase' of undefined"
I tried to debug (because the error is obscure to me and no line in my code is indicated) and noticed that this particular line:
this.state.bookTitles.push()
causes the error.
Please help!
Edit
The error is caused by a webpack var injection function:
function autoGenerateWrapperClass(type) {
return ReactClass.createClass({
tagName: type.toUpperCase(),
render: function() {
return new ReactElement(
type,
null,
null,
null,
null,
this.props
);
}
});
}
findDOMNode() uses the toUpperCase() function which actually is called on a null.
Example
var x = null
x.toUpperCase()// results in this error.
If you could post the findDOMNode() code, we could trace out the error.
OR
Make sure that the toUpperCase() is called on a non-null object.
My appologies for the poor quality of this post.
I resolved the issue.
Finally, the problem came from the included component:
<ToReadList bookTitles={this.state.bookTitles} />
The error appeared when this.state.bookTitles.push(React.findDOMNode(this.refs.bookTitleInput).value.trim()); was called because bookTitles triggers the error inside the component when it is not empty (i.e <ToReadList bookTitles={["mastery", "foundation"]} /> triggers exactly the same error)
The compenent in question's code is as such:
'use strict';
var React = require('react');
import {ToReadListItem} from './todoreadlistitem.js';
var ToReadList = React.createClass({
render: function() {
return (<ul>
{this.props.bookTitles.map(function(bookTitle){
return (<li>
<ToReadListItem bookTitle={bookTitle} isChecked={false}/>
</li>);
})}
</ul>);
}
});
module.exports = ToReadList;
Changing this line:
import {ToReadListItem} from './todoreadlistitem.js';
To this:
import ToReadListItem from './todoreadlistitem.js';
I know, it is not a great idea to mix es6 syntax with flat one, but I permit myself doing it since the app is for experimentation purposes.
I hope I helped to make things clearer.
I guess the problem is because you try to modify the state directly. Try this:
var newBookTitles = this.state.bookTitles;
var value = React.findDOMNode(this.refs.bookTitleInput).value.trim();
newBookTitles.push(value);
this.setState({bookTitles: newBookTitles});
I hope it will solve your problem.
Importing component with incorrect name gave me the same error.
I had imported it as
var AreaChart = Charts.AreaChart;
where as in Charts.js it was exported with a small 'c' :
Areachart: Areachart
Changing it to AreaChart: Areachart in Charts.js while exporting solved it.

Reflux stores not listening to actions

Edit:
I feel silly now. The problem was I wasn't requiring my store anywhere in my code, so it was never actually being created.
My refluxjs store is not calling its callback when I call the action it's listening to. Here is the relevant code:
Actions:
module.exports = require("reflux").createActions([
"createUser"
]);
Store:
var userActions = require("../actions/user-actions");
module.exports = require("reflux").createStore({
listenables: userActions,
onCreateUser: function() {
console.log("onCreateUser called", arguments);
}
});
Component that fires the action:
var React = require("react"),
userActions = require("../../actions/user-actions");
var Login = React.createClass({
getInitialState: function() {
return {
name: ""
};
},
updateName: function(event) {
this.setState({
name: event.target.value
});
},
// Action gets called here
submit: function(event) {
event.preventDefault();
console.log("Creating user", this.state.name);
userActions.createUser(this.state.name);
},
render: function() {
var name = this.state.name;
return (
<div className='login'>
<form onSubmit={this.submit}>
<input value={name} onChange={this.updateName} />
<button>Create</button>
</form>
</div>
);
}
});
When I submit the form in the Login component, the submit method is called without throwing any errors, but the onCreateUser method of my store is never called.
The examples on the reflux github page seem fairly straightforward and this is almost exactly the same as the example for using the listenables property on a store.
Any help would be greatly appreciated.
Since stores usually are hooked up to a component, and be required in that way, you could create a test component that just logs out to the console:
var store = require('path/to/your/store'),
React = require('react'),
Reflux = require('reflux');
var ConsoleLogComponent = React.createClass({
mixins: [
Reflux.listenTo(store, "log")
// you may add more stores here that calls the log method
],
log: function() {
console.log(arguments);
},
render: function() {
return <div />
}
});
You can then put this console component where ever and just have a sanity check that the store works.

A good way of testing jsx components that used RequireJS define from jest

I want to test ReactJS component with jest but have a trouble because component using RequireJS define. This is example code (truncated).
// component.js
define(function(require){
var React = require('react');
// code
var _ = require('underscorejs');
var somename = React.createClass({
propTypes: {
},
getDefaultProps: function () {
return {
};
},
render: function () {
// implementation
}
});
return React.createClass({
// implementation
});
});
When I tried into test:
import ComponentName from '../path/to/ComponentName.jsx';
i receive this error:
Runtime Error
ReferenceError: define is not defined
I was think about to process source with preprocessor. It is possibillity to use scriptPreprocessor option but this is some kind of hacky from my point of view.
I would be very grateful for any ideas and recommendations.

Categories

Resources