Scoping 'this' within a reactjs component - reactjs

While building my first reactjs component, I got the familiar "undefined is not a function" when trying to use a helper (makeWorkSiteUrl) because the this scope had changed away from being that of the component.
Of course, I just did what most JS developers would do and declared that=this before I made my function call to solve the problem.
However, it occurred to me that this is probably a common problem. So there might be a 'better' or 'react' way of achieving the same thing. Or, it may be an indication of poor design of this component. Is there a style or method that is preferred or available instead of that=this to access a components internal functions/properties?
"Undefined is not a function":
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = this.makeWorkSiteUrl(worksite.id) //Fail
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
Works as expected:
var WorkSiteQuickList = React.createClass({
propTypes: {
data: React.PropTypes.object.isRequired
},
render() {
that = this;
var workSiteNodes = this.props.data.work_sites.map(function (worksite) {
var linkUrl = that.makeWorkSiteUrl(worksite.id) //OK
return (
<WorkSiteQuickListItem workSiteName={worksite.name} linkUrl={linkUrl} />
);
});
return (
<div>
{workSiteNodes}
</div>
);
},
makeWorkSiteUrl(workSiteId) {
return "/worksite/"+ workSiteId;
}
});
I'm sure this question will be closed, but I'd rather ask it than miss a critical part of the "framework".

Here are some common patterns to deal with this scoping:
Utilizing an es6 transpiler (like the JSX transformer that you're currently using, or babeljs which happens to support JSX), use arrow functions which are scoped to the outer context (aka lexical scoping).
this.props.data.work_sites.map( (worksite) => { .... return ... } )
Pass in this as the second argument of Array#map
Chain bind onto the function you pass into Array#map
function() {}.bind(this)
Update: I've had a lot of trouble lately with =>, this resolving to window when paused at a breakpoint in the chrome dev tools within the render() method. Originally I thought it was a babeljs bug. However, turns out it's actually a failure of the dev tools ability to understand that source maps actually replace this with _this.

Related

ReactJS: componentWillUnmount not working across project

I have an issue with ReactJS. Specifically componentWillUnmount is not being called across the project at all (a semi-large corporate website). I will list the steps I have taken to diagnose and pinpoint the issue:
I am using a simple console.log message to test, to exclude problems inside the function
I have placed it in different jsx files in the project, to exclude function positioning problems
I have checked against switching pages in the app and loading a different website altogether
I checked to see whether the function is called from parents, siblings or children, since I've found competing lifecycle calls can cause neither to work, but it's the only one in the project so far
I tried it on a different branch with no effect
I tried it on a colleague's computer with no effect
A different lifecycle function (componentWillMount) works fine
I am using ES6 with react 15.1.0, react-bootstrap and react-validation. The relevant code is below, but keep in mind I have placed the function in numerous places and it does not appear to get called anywhere.
export default class YourData extends React.Component {
constructor(props){
super(props);
this.getMainBookers = this.getMainBookers.bind(this);
this.bookingTravelCompanyForms = this.props.your_data.bookings.map(
(booking, i) => {
var mainBookers = i > 0 ? this.getMainBookers : false;
return (
<BookingTravelCompanyForm booking={booking} key={i}
mainBookers={mainBookers}
onInputChange={this.props.onInputChange}/>
);
}
);
}
componentWillMount(){
this.props.initializeInput();
}
componentWillUnmount(){
console.log('willunmount yourdata');
this.props.saveInput();
}
getMainBookers() {
var mainform = this.bookingTravelCompanyForms[0];
return mainform.props.booking.company;
}
handleSubmit(event) {
event.preventDefault();
// Emulate async API call
setTimeout(() => {
this.refs.form.showError('username', <span onClick={this.removeApiError.bind(this)}
className='form-error is-visible'>API Error. Click to hide out.</span>);
}, 1000);
}
copyTravelCompany() {
var travelCompany = this.bookingTravelCompanyForms[0];
this.setState({
travelCompany: travelCompany
});
}
render() {

react-native module export type

I love RN but one issue that is really annoying me is lack of conventions. I'm used to it a bit as a js developer. But using ES6 or not
render() { vs. render: function() {
is one thing. What I really can't understand is when I saw the WebView module export example as
exports.examples = [
{
title: 'WebView',
render(): ReactElement { return <WebViewExample />; }
}
];
And sometimes I see
export default PDFView;
I'm used to
module.exports = WebViewExample
Returning an object breaks my code and forces me to think about what type I should expect from each component. I understand the value of returning an object but it seems like a bad thing to start introducing in the docs. End of rant. What is default is for?

How to transfer props to the deepest component fast?

I render React on a server.
I have a common chain of three components. I need to pass a units object (just plain js object {name: 'example.com'}) to the deepest component <Foo /> in the chain from the most outer component <FooBox />. For now I have to pass my unit object down through every component as a this.props.units. I doesn't look nice, it looks like some bad practice to me:
// my-react-components.js file
var FooBox = React.createClass({
render: function() {
return (
<div>
// here I pass 'units'
<FooList data={this.props.data} units={this.props.units}>
</div>
);
}
});
var FooList = React.createClass({
render: function() {
return (
<div>
// and here I pass 'units'
<Foo myId={this.props.data[0]} units={this.props.units} />
</div>
);
}
});
var Foo = React.createClass({
render: function() {
var units = this.props.units; // and only here I use `units`
return (
// only here I need `units`
<div dangerouslySetInnerHTML={{__html: units[this.props.myId].name}}>
</div>
);
}
});
On server-side my code is as follows (a Node.js app):
var React = require('react');
var ReactDOMServer = require('react-dom/server');
var FooBox = require('../my-react-components.js');
var data = [...some data here...];
var units = {name: 'example.com'}; // this is my 'units' object
var html = ReactDOMServer.renderToString(React.createElement(FooBox, {
data: result,
units: units // so 'units' comes yet from here
}));
My question is:
Is it the only way to get units in <Foo />? Only by passing it down the whole chain as a props? Is there a way to get units in <Foo /> easier, avoiding step-by-step props passing?
you can use context instead of props.It lets you pass data through the component tree without having to pass the props down manually at every level https://facebook.github.io/react/docs/context.html
For fast pass down {...this.props}.
For clear logic I think we must pass it down
In my opinion, the large degree of redeclaring and reassigning the same properties down the component hierarchy tree is one of the more irritating features of React. It could be argued that this is a strength: the data flow is explicit and makes your application easy to reason about. But personally I find such repetition to be jarring.
Certainly context, as mentioned by vistajess, is one solution. But I am loath to invest much in an experimental API.
Another solution is to use Flux and have store listeners spread across different components. (In Redux for example, these would be contected components.) Of course this somewhat increases the complexity of your components.
Or finally you can just grin and bear it. (It's generally what I do.) Constantly re-typing the same properties may be annoying, but as far as code smells go its pretty minor. Bear in mind too that React is still fairly new and its API is rapidly evolving. In time, surely some solution to this problem will be adopted. (The mainstreaming of context perhaps?) For now, be comforted by the fact that React's weaknesses are far outweighed by its strengths.

React JS Component "wait for props"

This is not a question as much "how to make this work" as much as it is a "was this the best way." Here's my code:
/**
* React Static Boilerplate
* https://github.com/koistya/react-static-boilerplate
* Copyright (c) Konstantin Tarkus (#koistya) | MIT license
*/
import React, { Component } from 'react';
// import './InputWidgetText.scss';
import ContentBlock from '../ContentBlock';
var i = 0;
var contentBlocks = [];
var ContentContainer = React.createClass({
addNewBlock: function(){
i++;
contentBlocks.push(<ContentBlock key={i} index={i}/>)
this.forceUpdate();
},
render: function(){
if (this.props.inputs) {
contentBlocks = this.props.inputs.map(function(item, index){
i++;
return(<ContentBlock key={index} index={index} content={item} />)
});
}
return (
<div>
{contentBlocks}
<button onClick={this.addNewBlock}>+</button>
</div>
)
}
});
export {ContentContainer as default};
The problem is that every so often on a refresh the props.inputs are not getting passed down to this component and throwing an error when I try to map undefined. So the simple solution is to put the map process in an if check for whether or not the props are there yet - is that actually the right way to handle this? My data is passed in via a reflux mixin on the parent. I just feel like there might be a more proper way to handle this. Thanks for the feedback!
May I strongly suggest you refactor your code to do away with the file variables i and contentBlocks.
The contentBlocks variable seems completely unnecessary, whilst your i variable should be part of the state. Whilst you're at it, give i a more meaningful name, e.g. blockCount.
getInitialState: function () {
return {
blockCount: 0
};
},
Then define your click event handler to modify the state:
addNewBlock: function () {
this.setState({
blockCount: this.state.blockCount + 1
});
},
Every time you call setState(), React will trigger a re-render. You should never need to call forceUpdate().
Finally, your render() function should return its content based SOLELY on this.props and this.state. That is, for any given props and state, the output will be predictable. Think of this.props and this.state as input parameters to the render() function. That is all render() can, or needs to, know about.
I won't try to write the render() function as I'm not sure exactly what you're trying to achieve with this component. But for a given this.props.input and this.state.blockCount (or whatever you choose to use as props and state) you should know exactly what you're outputting.
I know I haven't directly answered the question you put, but I hope this clarifies some React concepts.

Output object name other than React with jsx syntax

with React v0.12 the #jsx pragma is gone which means it is no longer possible to output jsx with anything other than the React.METHODNAME syntax.
For my use case I am trying to wrap the React object in another object to provide some convenience methods thus, in my component files, I want to be able to write:
var myConvenienceObject = require('React-Wrapper');
var Component = myConvenienceObject.createSpecializedClass({
render: function () {
return <div />
}
})
However the jsx compiler automatially converts <div /> into React.createElement("div", null)
With older versions of React it was possible to handle this using the pragma at the top of the file. However, since that has been removed, I was wondering if there was any way currently to change the name of the object compiled by jsx so <div /> would be transformed into myConvenienceObject.createElement("div", null)
No, it's no longer possible to use a custom prefix for JSX. If you need to do this, you'll need to modify the JSX transform code, or create a fake React.
var React = require('react'), FakeReact = Object.assign({}, React, {
createElement: function(component, props, ...children){
// ...
// eventually call the real one
return React.createElement(component, props, ...children);
}
});
module.exports = FakeReact;
And then to use it you import the fake react and call it React.
var React = require('fake-react');
// ...
render: function(){ return <div />; }
If you would like to make some elements contains in your myConvenienceObject, you could consider the children props as shown in the doc. But this may need some changes in the myConvenienceObject too, to accept the children.
By the way, i'm not sure where is this createSpecializedClass functions comes from and what it does

Resources