How the props of react.js are declared - javascript

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.

Related

Why is this Vue prop not reacting to change?

I have a Prop in my component that is a User object, I then have this function:
onChange: function(event){
this.$v.$touch();
if (!this.$v.$invalid) {
this.$axios.put('update',{
code:this.user.code,
col:event.target.name,
val:event.target.value
}).then(response => {
this.user[event.target.name]=event.target.value
});
}
}
I can see in the Vue console debugger that the correct attribute has been updated, this attribute exists when the component is created but the template where I reference it does not refresh:
<p>Hi {{user.nickname}}, you can edit your details here:</p>
This is all within the same component so I'm not navigating to child or parent. I'm sure props have been reactive elsewhere in my code?
Ok, it seems this is intended behaviour. According to the documentation
https://v2.vuejs.org/v2/guide/components-props.html in the scenario that I have it should be handled as:
The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case,
it’s best to define a local data property that uses the prop as its
initial value:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
Usually components should be reactive to Props, though i have had experiences where it was non-reactive so i added the prop to a watcher and put the functional call there.
props: ["myProp"],
watch:{
myProp(){
// ... your functions here
}
}

How to get changes in Vue updated hook?

If I have a Vue component like:
<script>
export default {
updated() {
// do something here...
}
};
</script>
is there anyway to get the changes that resulted in the update? Like how watch hooks accept arguments for previous and next data?
watch: {
someProp(next, prev) {
// you can compare states here
}
}
React seems to do this in componentDidUpdate hooks, so I'm assuming Vue has something similar but I could be wrong.
The updated lifecycle hook doesn't provide any information on what caused the Vue component instance to be updated. The best way to react to data changes is by using watchers.
However, if you're trying to investigate what caused an update for debugging purposes, you can store a reference to the state of the Vue instance's data and compare it to the state when updated.
Here's an example script using lodash to log the name of the property that changed, triggering the update:
updated() {
if (!this._priorState) {
this._priorState = this.$options.data();
}
let self = this;
let changedProp = _.findKey(this._data, (val, key) => {
return !_.isEqual(val, self._priorState[key]);
});
this._priorState = {...this._data};
console.log(changedProp);
},
This works because properties prepended with the underscore character are reserved for internal use and are not available for binding. This could be saved in a mixin to use whenever you needed to debug a Vue component this way.
Here's a working fiddle for that example.

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

Is it correct to initialize state of child component via props?

I need to initialize state of child component from parent one. So I do it by the following way:
var Timer = React.createClass({
getInitialState: function () {
return {timer: this.props.timer};
},
render () {
return <div>{this.state.timer}</div>
}
});
var App = React.createClass({
getInitialState: function () {
return {timer: 1000};
},
render () {
return <Timer timer={this.state.timer}>
}
});
Is it correct to initialize state of Timer component this way?
I think it is fine to do it like that.
In your case, I assume you will change the value of timer inside the component (say, by some user interactions). Because a value on state is supposed to be some instance variable, whose value may change to reflect the component status. But be reminded that changing the state.timer value will not change the timer value outside.
If you will not change the value of this.state.timer inside the component, you can just use it like:
render () {
return <div>{this.props.timer}</div>
}
Note:
This isn't really a React-specific tip, as such anti-patterns often occur in code in general; in this case, React simply points them out more clearly.
Using props to generate state in getInitialState often leads to duplication of "source of truth", i.e. where the real data is. This is because getInitialState is only invoked when the component is first created.
Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble.

Pass this.refs as property in jsx in React.js

I'm trying to pass 1 node as a property of another React component like this:
render: function() {
return (
<div>
<div ref='statusCircle'></div>
<Popover trigger={ this.refs.statusCircle }></Popover>
</div>);
);
}
But in the Popover, this.props.trigger is NULL.
Is there anything wrong with my code?
How can I pass a node-ref to another React component as property?
You've misunderstood the component lifecycle in React.
See here: Link
See this fiddle. https://jsfiddle.net/uzvoruf7/
Open your console, inspect the code for the "Composite" component, and see the lifecycle hooks.
var Popover = React.createClass({
render: function() {
return (<div>This is a pop-over</div>);
}
});
var Composite = React.createClass({
componentDidMount: function() {
console.log(this.refs.statusCircle); //ok, exists.
},
render: function() {
console.log(this.refs.statusCircle); //doesn't exist, sorry.
return (
<div>
<div ref='statusCircle'></div>
<Popover trigger={this.refs.statusCircle}></Popover>
</div>
);
}
});
ReactDOM.render(
<Composite />,
document.getElementById('container')
);
"refs" come alive once the DOM has been rendered.
Therefore, it follows that inside that return statement, the dom has not been rendered yet, hence the reference is null (or all references are null so to speak).
However, inside componentDidMount, you can see that your references are available just as one would expect.
This is a common error: a possible code smell that needs refactoring. Usually (not always), passing down dom-references is indicative of an imperative thought process and is not the React way. I would suggest an improvement but I'm not aware of your use-case.
After typing this I realized it's really not an answer to the original question but instead a follow-up to your request for suggestions in your comment above. If you really don't believe it should stay, I'll delete it but it's too big for a comment, sorry.
Reference material
You must be using an old version of React, so this may not look right to you at first, but you could track that information using state in that parent component by doing
ref={ function ( element ) {
// at the top of render() put
// var self = this;
self.setState({
circleWidth: element.offsetWidth,
circleHeight: element.offsetHeight
})
}
Assuming those values change over time, you'll want to add an event listener for that change (which can be added inside that ref setup) and have it run that setState again when you need it to re-render.
As for <Popover trigger= you'll want to do something to the effect of:
<Popover trigger={this.state.circleWidth > 999} />
...where 999 is whatever your trigger value would be. If it returns true, then you render Popover. If not, you destroy it. Both situations would be handled inside Popover but will not need to touch that div
Of course, good practice in React is to do that comparison at the top of render() and place the result into a variable like isTriggered.

Categories