in a react component, how to get `this` in static function? - javascript

attempting to create a static function within a react component. the function uses this to get its data, but this is out of scope when the function is called.
here is a very simple example:
var Test = React.createClass({
val: 5,
statics: {
getVal: function() { return this.val }
},
render: return( <div>{this.val}</div> )
});
Test.getVal(); => undefined!!
obviously this has lost its scope when Test.getVal() is called. how to get this inside the getVal() function?
fyi, the following standard javascript parent approach does not work:
Test.getVal.apply( Test ); => undefined

Check out the docs on statics.
Whatever you put in statics is not going to have the context of an actual React component instance, but the val property you're defining is a property of an actual React component instance. It's not going to exist before you actually render the component, because that's when all the non-static properties are constructed. Statics are supposed to be component-related functions that are usable outside the context of an actual instance, just like for example static functions in C# and many other languages.
It simply doesn't seem to make sense to want to access a React component instance from a statics function. Maybe you need to think over what you're actually trying to achieve. If you really want to be able to access a specific component's properties, then I guess you can pass the instance as an argument to the static function, but then of course that would be usable once you have actually constructed a component.

Ahh ok misunderstanding. If you need to somehow be able to call this method whenever then your val must be located in statics as well but your render function would then have to reference Test.val instead of this.val. If this isn't a requirement though it would be best to stick to props/state and accessing things from within the component since the component will not autoupdate based on changes to the val.
var Test = React.createClass({
statics: {
val: 5,
getVal: function() {
return this.val
}
},
render: function(){
return( <div>{Test.val}</div> )
}
});
console.log('VAL IS' , Test.getVal());
Link to fiddle with example https://jsfiddle.net/dgoks3Lo/

Related

How the props of react.js are declared

I'm new to React. I'm not understanding a part in this code:
var HelloMessage = React.createClass({
render: function() {
return <h2>{this.props.message}</h2>;
}
});
var TextBox = React.createClass({
getInitialState: function() {
return { isEditing: false }
},
update: function() {
// Where is props.update defined? //
this.props.update(this.refs.messageTextBox.value);
this.setState(
{
isEditing: false
});
},
edit: function() {
this.setState({ isEditing: true});
},
In the code I can't find the props declaration for update. But looking through the code we should see "update" as a property of the TextBox component.
I'm not seeing an explicit declaration of this.props.update within any render method.
How/Where is props.update defined?
So inside the HelloReact component render method, a few TextBox components are returned like so:
...
<TextBox label='First Name' update={this.update.bind(null, 'firstName')}>
...
Now here what is happening is that HelloReact is passing a prop named update to this TextBox component. This means that inside the TextBox component I will be able to use this prop with this.props.update. Every prop that is passed down from the parent will populate this.props of the child. In this specific case we are passing down label and update.
Now inside the TextBox component we will be able to access these props intuitively with this.props.label and this.props.update. Inside this component it's define a private method that is called update, this is the code from the snippet you posted with better formatting:
...
update: function() {
this.props.update(this.refs.messageTextBox.value);
this.setState({ isEditing: false });
},
...
So here we are calling this.props.update which is the prop that was passed down from the parent in HelloReact. The reason we are wrapping this call in a private method is because on top of being able to call this.props.update() we also want to do something else, in this case we want to update the state of the TextBox component as well.
I hope this explanation was clear enough. I suggest reading about React from the official docs which are pretty amazing, or watch any of the many tutorials online. These are key concepts of React and you need to understand them properly in order to be able to develop in React.
For this case you might wanna read this, which comes from the offical docs and is about props.

Use props instead of state

I know if you want to alter something within a component itself you use state, and when the emit is external then u use props to receive it. But today I stumped across this example
var Label = React.createClass({
handleClick: function(){
console.log("Click");
this.props.children = "Text After Click";
this.setState({liked: false});
},
render: function () {
console.log("Render");
return (
<p ref="p" onClick={this.handleClick}>{this.props.children}</p>
);
}
});
Used props instead of state to change the text a value of a button. I'm confused now. The link to the source is here http://myshareoftech.com/2013/12/unit-testing-react-dot-js-with-jasmine-and-karma.html
I don't know about the source but when i tried above code it throws this error:
Uncaught TypeError: Cannot assign to read only property 'children' of object #<Object>.
It should not work because the basic property of the props is, as per DOC:
Props are Read-Only, Whether you declare a component as a function or a class, it must never modify its own props. All React components must act like pure functions with respect to their props.
Check the fiddle for error: https://jsfiddle.net/pjnp6yza/
Reference: https://facebook.github.io/react/docs/components-and-props.html#props-are-read-only

React: Can't call prop function when it is inside of another function?

I am trying to move over the Auth0 login function as described in their tutorial. I am able to get it work if I use it like this:
<button className="btn" onClick={this.props.route.auth.login.bind(this)}>test</button>
but if I set up the button to call a function I define above the render function like this:
login() {
this.props.route.auth.login.bind(this);
}
And change the onclick to be like this:
onClick={this.login()}
or
onClick={() => this.login()}
Then the auth login modal never opens and i receive no error. Also i added a console.log to login() and I can see it in the console, but the actual login modal never opens? It works in the first example, but not in the others.
The reason I am attempting to move this into a function is because I would like to pass the login function down into a child component later, and I was unable to do so and I believe this to be the root issue thats preventing me.
bind does not call your function:
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called. docs
Also, you are setting the value of onClick prop to the return value of login. If you want to pass a reference to the function, you have to do it without the ().
Your code should look like this:
<button className="btn" onClick={() => this.login()}>test</button> <!-- You need to keep a reference to `this`, hence the binding -->
Then:
login() {
this.props.route.auth.login();
}
I edited the answer so that it uses an arrow function. However, I prefer not doing that, since it makes the code a bit cumbersome, and rather bind all the functions in the constructor, like #patrick-w-mcmahon did.
Let's say you have a container MyContainer and this container renders a view called MyView. This view has a button that calls a method. MyContainer is going to pass to the MyView the method it needs to use.
MyContainer:
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.myFunc = this.myFunc.bind(this);
}
myFunc() {
console.log("hello world");
}
render() {
return <MyView myClick={this.myFunc}/>;
}
}
MyView:
const MyView = ({ myClick }) => {
return <button onClick={myClick} />;
};
MyView.propTypes = {
myClick: PropTypes.func
};
export default MyView;
You pass the needed function from the container to the view and the view calls its parents function from props. the use of bind() sets this scope to the current scope so that when you call this from a different scope it is going to be the scope of the bind. When you are in the render you run a different scope so you must bind your functions to the current class scope so that this.myReallyCoolFunction() is pointing to the correct scope (your class scope).
.bind() will only bind the object and arguments but won't call (run) the function.
TL;DR Just use .call() instead of .bind()
instead of .bind() you can use
.call(this, args) which is basicaly the same as bind only that call will call (run) the function.
you could also use .apply(), which is basicaly the same as .call() but takes an array with the arguments instead of object like .call()
this way you can avoid arrow functions in you jsx render()
and kind of keeping the line of thought with react.
something like ->
login() {
this.props.route.auth.login.call(this);
}
When you call props function through return(JSX) React takes care of calling it once propagation ends.

Assigning a property with ES6 in a React Component

I am new to ES6 and still trying to grasp the concepts of the new specifications, i am currently working on a component in React where i need to make an ajax call and store this response in an object. Then use this object to the map the necessary elements
My component looks like the following
export class App extends Component {
search(){
//make ajax call
response = obj.responseText;
}
getValues(){}
render(){
let result = response.data.map(this.getValues);
return(
<div onKeyDown={this.search.bind(this)}>{result}</div>
)
}
}
How do i declare the "response" variable globally which gets assigned the data from ajax call "obj.responseText"?
It seems like you know what you want to achieve, but are a little confused about how to get there.
I would highly recommend reading the React documentation before you go any further.
Why not global variables?
How do I declare the response variable globally?
In short, don't. Global variables are well-documented as being evil. One instance of this component in a page with a global variable to store its search results would be fine, but imagine if you had two or more instances - they would all share/overwrite each other's search results.
Introducing state
Instead, you want to use React's component state functionality to store your search results.
You can set an initial state by setting a component's this.state in its constructor, (or in ES5, define a getInitialState method on the component).
Then, any time you want to update the component's state, you can call its this.setState(...) method, passing in a new state object. This will also trigger a re-render of the component.
Example
Here is a simple implementation following the above pattern:
export class App extends Component {
// Set the initial state of the component in the constructor
constructor(props) {
super(props);
this.state = {};
}
// This gets called when your component is mounted
componentDidMount() {
// Here we make our AJAX call. I'll leave that up to you
performMyAjaxMethodDefinedSomewhereElse(result => {
// We call this method to update `this.state` and trigger re-rendering
this.setState({ result });
});
}
render() {
// If we haven't received any results yet, display a message
if (!this.state.result) {
return (
<div>No results!</div>
);
}
// Iterate over the results and show them in a list
const result = this.state.result.map(text => (<li>{text}</li>));
// Display the result
return (
<ul>{result}</ul>
);
}
}
Naturally, if you don't want the AJAX call to fire off immediately, you can use a very similar approach, replacing componentDidMount with an event handler which looks almost identical.

Setting a field directly on the class definition in ReactJS

Is it a good practice to do this in ReactJS?
var Component = React.createClass({
render: function () {
return (<div></div>);
},
field: 'value', // is this safe?
method: function () {
// do something with field
}
})
Before starting to suggest that I should use this.props or this.state, for me it's not the case, because those are fields that do not affect rendering in any way directly, they just work together to control the rendering.
I would like to use the React class as I do with regular javascript 'classes'.
My main concern here is how those fields and methods are handled inside React, and if the fields are set on the instance itself or directly on the prototype, which would not be suitable at all for what I need.
I ran a quick test and it seems that the fields are set on the instance, and the methods on the prototype, which is ideal. But is this the expected and documented behavior? And is this safe for future versions?
I think it can work the way you are doing and that it's safe. However if I understand well you are proceeding data calculation/transformation directly in the view.
So I would advise that you remove this logic from the view and treat it in the model part of a mvc or mv*, in your backbone models, or in your flux store for example.
This way you won't be mixing data transformation logic and pure rendering.
I would say so, I have been using things like this for a while and have not seen any issues. For example, let's say you want a handler of some sort that you want to pass to nested components, you would create the function in this component and pass it as a prop to a child. I believe they have examples that use similar concept in the ReactJS Facebook site.
Under the hood React is just looping through the properties of the object you pass to createClass and copying them to the prototype of the Component. Primitive values like strings or numbers obviously cannot be copied by reference, so don't get shared across all instances, whereas objects, functions, arrays and so on will.
If you want to work with values that are just local to the component instance you need to use the state API. I'm not sure what you mean by "[state and props] do not affect rendering in any way directly, they just work together to control the rendering". The whole point of props and state is that they work together to generate values to be used when (re)rendering.
https://facebook.github.io/react/docs/component-api.html
A React component should only render in response to either changing props or changing state. You cannot/shouldn't trigger a re-render by mutating other fields directly.
You need to think of your component as something closer to a pure function. State and props go in at the top, and static VDOM/HTML comes out.
I would re-write your example as,
var Component = React.createClass({
getInitialState: function () {
return {field: 'value'};
},
render: function () {
var field = this.state.field;
return (<div>{field}</div>);
},
method: function () {
var field = this.state.field;
// do something with field
this.setState({field: 'anotherValue'});
}
})

Categories