Sometimes in tutorials I see people returning 'this' from their render function. Is this now obsolete?
render : function() {
...
return this;
}
The official document still says:
A good convention is to return this at the end of render to enable
chained calls.
http://backbonejs.org/#View-render
It is not obsolete. You want to return 'this' from your render function to enable chained calls. This means that you can use the 'el' property to manipulate your HTML. This answer has a good explanation of this issue.
Related
Does anyone know what happened to 'this'?
console.log('check 1', this) //{activateLasers: ƒ, …}
Object.keys(modelData).forEach(function(key, index1) {
console.log('check 2', this) //undefined
The context of this changes inside map.
Array.prototype.map() takes a second argument to set what this refers to in the mapping function.
You can explicitly pass it to the map function to preserve the context.
array.map(function(i) {
...
} , this)
In your case
array.forEach(function(key, i) {
....
}, this)
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context
array.map((i) => {
...
})
It looks like you're writing code in strict mode. this is undefined because that's how the language works.
this in javascript is a syntactic construct. When you call a class or object method you usually do it in a way that looks like obj.method(). The language sees the syntactic pattern with the . and () and makes this obj inside method. If you ever don't see that pattern, (and are not using an => function, it should be a good cue that this might be undefined or window.
I am learning react and in some videos the lecturers use function like this in their component.
function(){}
and sometimes they use arrow function like this
function=()=>{}
what are the different between these two? whenever I use function(){} I cannot call any props from state so I always use arrow function and it works very well.
Arrow function automatically binds this-context to your component.
With the normal function you would need to do that yourself in your components constructor like that:
this.func = this.func.bind(this)
When using the "fat arrow" function, i.e. myFunc = () => {}, if you try to access this you will receive access to the surrounding function's this. This is because the fat arrow function does not bind it's own this.
When you use myFunc() {} you are binding this and scoping it to that function.
I am coming from angular world. And I am still kinda new to react.
One question that I encountered is that:
In angular, we have $watch to watch one scope variables to change and update other variables. like watch B,C,D, and change of B,C,D will affect variable A
In react, I am trying to do the same thing. However, I am calling to setState(B,callbackB) to update A. A has a setState that has an impact in render
It seems like doing such works correctly for variable B. However, updating A will occur in next render cycle. And this.forceUpdate() doesn't seems work.
Is there anything that I am doing wrong?
Thanks
An example would help clarify your situation, but depending on what "updating A" entails, you could move it to your render function. E.g.
class Component extends React.Component {
handleUpdate(B) {
this.setState({B})
}
computeAFromB(B) {
...
return A
}
render() {
const A = this.computeAFromB(this.state.B)
return <div>{A}</div>
}
}
When transitioning from Angular to React, it's important to keep in mind that scope !== state. This may be helpful: https://facebook.github.io/react/docs/thinking-in-react.html
You cannot rely on setState to update instantly. Try passing the new value explicitly to setState A.
Here's my example code, I think I found an answer already.
https://jsfiddle.net/yoyohoho/Lo58kgfq/1/
in the example code in jsfiddle. The input field is a required field.
And the button should be disabled if there is nothing in the field.
The problem is that if you type something and you erase it, button is still active, until you type in 1 more key, which is next cycle.
I use input1Err to determine if formError should be disabled in checkErr()
checkErr(){
if(this.state.input1Err == false){
this.setState({formErr: false });
}else{
this.setState({formErr: true });
}
}
This is the reason that why the view change happen in next cycle. Because setState is asynchronous
I was using this.state.input1Err to determine formErr, which may yet be changed before the if statement there.
So I changed to the following closure, which solves my issue.
checkErr(){
const self = this;
(function(j){setTimeout(function(){
if(self.state.input1Err == false){
self.setState({formErr: false });
}else{
self.setState({formErr: true });
}
},10)})(self);
}
This seems be a quick fix. However, what if there is ajax call and hooked up to state.input1Err. Is there a way I can watch this variable, so when it changes complete, I can have some sort of callback?
Thanks
I have been struggling with trying to migrate my React code from ES5 to ES6. As I have found out by now, this is no longer automatically bound which causes all sorts of hell.
I am trying to figure out by trial and error what objects are being passed around. So far I can find everything and adjust accordingly. However when it comes to this.setState I am having problems because it is not visible in console.log!!!! See screenshot in ES5:
and here is the same kind of code in ES6:
Please teach me how to fish i.e. help me figure out how to understand when an object has this.setState or not?
things i have tried
from googling around i understand you might be able to default bind everything by changing the base component. unfortunately this did not work when it came to this.setState. It looks identical to the ES5 version of this in console so I concluded that setState is still not being bound somehow
To oversimplify how this works in JS:
If you call a function as an object method (e.g., instance.foo()) then this refers to that object instance.
If you call a function by itself (e.g., foo()), then this is either undefined or the global object, depending on whether strict mode is in effect.
If you take a reference to an object method then call it, that means you're calling it by itself, even though it was originally an object method. (E.g., var bar = instance.foo; bar();.
Again, this is an oversimplification; MDN has details.
As this applies to React, and as explained in the React documentation on "Handling Events":
You have to be careful about the meaning of this in JSX callbacks. In JavaScript, class methods are not bound by default. If you forget to bind this.handleClick and pass it to onClick, this will be undefined when the function is actually called.
In your code, you render your RawInput as
<RawInput value={this.state.value} updateValue={this.updateValue}/>
You're passing a reference updateValue function in as a simple function, so this will not be bound within updateValue.
Basically, any time you pass a function as a React prop, unless you've bound it yourself, it's likely an error. The symptom is typically that this is undefined. In your code, it's a little more complicated:
this.props.updateValue(modifiedValue);
The RawInput's updateValue property is the unbound function App.updateValue, but because you're invoking it as this.props.updateValue, it's being called as if it were a method of this.props - so this refers to the RawInput's props. That's why your console.log is showing an object with only two properties (start and updateValue): it isn't that setState isn't bound or went away, it's that updateValue wasn't bound, so this isn't what you expect within updateValue.
To fix the issue, as the React docs explain:
Use a fat arrow function: updateValue={(value) => this.updateValue(value)}
Use the experimental property initializer syntax: Replace updateValue(modifiedValue) {...} with updateValue = (modifiedValue) => {...}.
Not mentioned in the React docs, but an approach I often use: Bind updateValue yourself. For example:
constructor(props) {
super(props);
this.updateValue = this.updateValue.bind(this);
}
you can replace console.log with this:
console.shallowCloneLog = function(){
var typeString = Function.prototype.call.bind(Object.prototype.toString)
console.log.apply(console, Array.prototype.map.call(arguments, function(x){
switch (typeString(x).slice(8, -1)) {
case 'Number': case 'String': case 'Undefined': case 'Null': case 'Boolean': return x;
case 'Array': return x.slice();
default:
var out = Object.create(Object.getPrototypeOf(x));
out.constructor = x.constructor;
for (var key in x) {
out[key] = x[key];
}
Object.defineProperty(out, 'constructor', {value: x.constructor});
return out;
}
}));
}
any way, regarding your question, you can add a method like this:
updateValue = () => {...}
in m POV - es6 is cool and great. React components by es6' classes are useless. stick with createClass and you'll be fine (and have mixins if you want!)
Try Object.prototype.hasOwnProperty(). For example:
var X = function() {};
X.prototype.setSomething = 'a';
var x = new X();
x.setSomething; // log 'a' here
x.hasOwnPrperty('setSomething') // log false here
In your case, just console.log(this.hasOwnProperty('setState')).
You have to bind your updateValue function with the component in order to have the correct context (this).
In your case, your parent class BaseComponent allows you to use the herited method _bind like that :
class App extends BaseComponent {
constructor(props){
super(props);
this.state={value:'start'};
this._bind('updateValue');
...
I'm using jQuery to create event bindings in a ReactJS component's componentDidMount function, which seems like the right place to do this.
$('body').on('defaultSearchContext.registerQueryEditor', (function(_this) {
return function(event, component) {
_this.setState({
queryEditors: _this.state.queryEditors.concat([component])
});
};
})(this));
This code isn't actually run on componentDidMount, it's simply setting up the binding that later calls setState when the event fires. However, this generates the following warning every time this event triggers, which pollutes my console with dozens of warnings:
Warning: setState(...): Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.
I have tried moving the setState code to a separate function like onEvent and calling that from the binding in componentDidMount but the warning is still produced.
Ideally, I'd like to create the binding in the proper place, indeed, there is some issue with doing it in componentDidMount. If not, I'd like to know if it's possible to silence the warning, or whether I should perhaps file a bug for ReactJS itself. If it helps, I'm using ReactJS 0.14.3 (latest at this time).
This is similar to, but not the same as React Js onClick inside render. In that case, the solution is to return an anonymous function to onClick, but that doesn't seem applicable to my situation.
You are trying to coordinate events between independent components. This is a fairly standard thing to do, and it doesn't require DOM events. The standard practice for doing this in React is to use a store/dispatcher pattern like Redux or Flux (I personally prefer redux). However, if this is part of a larger, not-completely-React application, then this may not be possible. If it is just for a small piece of an React app, it may still be overkill.
All you need is an object to coordinate events. An event is just a collection of callbacks, possibly typed or keyed. This requires nothing more than an object shared between two places. DOM Events are overkill; jQuery is overkill. You just need to trigger a callback.
This is a VERY SIMPLE event coordinator.
let simpleEventCoordinator = {
callbacks: new Map(),
getHandler(eventKey) {
let handler = this.callbacks.get(eventKey);
if (!handler) {
handler = new Set();
this.callbacks.set(eventKey, handler);
}
return handler;
},
registerCallback(eventKey, callback) {
this.getHandler(eventKey).add(callback);
},
removeCallback(eventKey, callback) {
this.getHandler(eventKey).delete(callback);
},
trigger(eventKey, data) {
this.getHandler(eventKey).forEach(c => c(data));
}
Keep a map of callbacks, which will be nameOfEvent => callback(). Call them when asked. Pretty straightforward.
I know nothing about how your components are structured, but you said they are independent. Let's say they look like this:
React.render((
<div>
<QueryManager />
<button onClick={() => simpleEvent.trigger('event')}>{'Update'}</button>
</div>
), document.body);
This is all your component needs to handle this event
componentDidMount() {
simpleEvent.registerCallback('event', this.update);
}
componentWillUnmount() {
simpleEvent.removeCallback('event', this.update);
}
update() {
//do some stuff
}
I've put together a very simple codepen demonstrating this.
Looking at the source code of where that warning is coming from, it appears that if some reference is maintained before an update is about to happen, it throws that warning. So maybe the way your mixing the jQuery events and react is creating a memory leak? Its hard to say exactly because of the lack of surrounding code to your snippet what else could be going on.