React: Return Statement - javascript

So I was reading on the Internet that
The vanilla JavaScript rule is, a return statement can only return one thing.
That one thing can be an array, an object, or React's >JSX case, a that contains multiple DOM elements.
Which Makes sense but then on the same place it was mentioned that
return [ ... cannot include a CSS class, style, an HTML attribute, ... but,
return <div classname="myClass" style={‌{color:"red"}} onClick={ ... }><p>A</p><p>B ...
can include a CSS class, style, an HTML attribute.
This statement is being little to confusing for me to understand.
"return [ ... cannot include a CSS class, style, an HTML attribute, ..."
[Question]: Can someone explain the above statement with example?
Also, this is a valid statement which we use in tutorial
return [
<p onClick={this.props.click}> Hey, I am {this.props.name}{this.props.children} and my age is {this.props.age} </p>,
<input type="text" onChange={this.props.changed} value={this.props.name} />
]
I guess we haven't used any html attribute above? but if we pass CSS class, or an HTML attribute such src or href, it won't work?

In JSX, return <someHtmlElement attribute='...'> is just a fancy syntax for a React.createElement('someHtmlElement... call, so essentially, you are still returning an object. Or, in case of your example return [ <p onClick...: an array of objects.
Also bear in mind that CSS class, style and HTML attributes only make sense in the context of an HTML element (simply put, between a < and a >), as those will all become part of the React.createElement call mentioned above. So this is why you can't directly return them in an array (i.e. return [ classname="myClass", style={‌{color:"red"}} ]): they don't have a meaning in "plain" JavaScript.
You can, however, return an array of HTML elements (which are essentially objects to JavaScript in this case), and those HTML elements of course can have CSS class, style and HTML attributes.
I hope this clears it up. When in doubt, just bear in mind that JSX simply ends up being JavaScript in the end, and try to think about what "vanilla" JavaScript would allow you to do.

what you see is 'jsx', a new syntax which came about when react was introduced. jsx looks like html, but gets converted to normal javascript function calls. You cannot use a file containing jsx and feed it to the browser. You will need some converter who converts the jsx code inside your file to javascript function calls. babel is the most famous converter of them all.
For e.g.
<div className='main' style={{backgroundColor: 'red'}}>abc</div>
gets converted to
React.createElement(
'div',
{ className: 'main', style: { backgroundColor: 'red' } },
'abc'
);
So, in your original question, what you are returning is not css properties or html, but whatever is returned by the function call React.createElement(). What does React.createElement return? It returns a plain javascript object. That object describes the html which has to be rendered. From your questions point of view, you are actually return an object.
And in your last example, therefore, you are returning an array of objects.
return [
<p onClick={this.props.click}> Hey, I am {this.props.name}{this.props.children} and my age is {this.props.age} </p>,
<input type="text" onChange={this.props.changed} value={this.props.name} />
]
P.S. You can check what javascript code your jsx will convert to here - https://babeljs.io/repl/

There is a strong difference between plain javascript syntax and React syntax. React use a syntax called JSX which thanks to compilers as Babel it is tanspiled JSX code in javascript.
To give you a better idea on what Babel does with JSX:
return [ <p />, <p className="hello" /> ];
it becomes:
return [React.createElement("p", null), React.createElement("p", { className: "hello" })];
You could visit https://babeljs.io/repl/ and see how transpiling works.

Related

Replacing string literal css class-name in js/react code with a declared constant?

Kinda new to the whole html/js/css/react world... So, let's say I have a react component that generates a div that I want to style, so I set
<div className={"my-class-name"}>
{// stuff here
}
</div>
Then in a .css file:
.my-class-name{
color : blue
}
Here "my-class-name" is a string literal, and string literals are bad-coding-101 in every language I've ever used, instead what to do is declare a constant once:
const MY_CLASS_NAME = "my-class-name"
and refer to the constant everywhere instead of the literal. For lots of reasons (you can change it in one place, you get compile-time not run-time errors, the IDE can know about it, etc.). But it doesn't seem like a css file can look up a javascript constant. Is there a way to do what I want? Am I thinking about this all wrong?
I tried googling, couldn't figure it out, any help is appreciated.

Can I nest JSX Tags into one another using traditional JS syntax?

const JSXParentTag = <div></div>;
const JSXChildTag = <p></p>;
Consider parentTag & childTag above. Is it possible to nest childTag in parentTag to look something like this:
<div>
<p></p>
</div>
using traditional JS syntax? For instance, something like this:
JSXParentTag.child = JSXChildTag;
P.S. I know you can write <div>{JSXChildTag}</div>. I'm wondering if I can nest them using traditional JS syntax as I'm sorting through multiple arrays of JSX Tags & it'd make it easier.
No, You can't. JSX is a syntax extension to JavaScript. Babel compiles JSX down to React.createElement() calls.
In your example <div> is compiled into React.create('div'). If you steel want to write in "traditional JS syntax" you can use createElement method.
React.createElement('div', null, React.createElement('p'));

Append index dynamically to attribute

I have this button element:
<button v-on:click="changeRecord(element)" v-b-modal.modal-5>Aendern</button>
it is generated dynamically inside a v-for loop.
Instead of hard coding the attribute name like above v-b-modal.modal-5 I want to concatenate it like this:
v-b-modal.modal-{{index}}
Is there a way to do this?
I'm using vue-cli 3 and bootstrap-vue.
I haven't used this framework before but looking at the second example from the docs I think something like the following should work.
<button v-on:click="changeRecord(element)" v-b-modal="`modal-${index}`">Aendern</button>
You will need to ensure that the variable index is made available when you set up the v-for
EDIT: For clarity, the above works because in VueJS the input to a directive is evaluated as an expression. The above example uses backticks string interpolation but the same can be done using pretty much any valid expression like "'modal-'+index" or based on some property on the item we are looping over "`modal-${item.id}`".
Unlike directives, class or other attributes are interpreted as plain strings unless they are bound using v-bind in which case they are treated as expressions. The example in the docs uses a simple string as an input so it's hard to tell from that particular example that it can be used in this way.
It is possible to add dynamic attributes like following
<p class="text" v-bind="options">{{ message }}</p>
Inside the computed, define the value for options
export default {
data:()=> {
return {
message: 'Hello world!',
id: 12345
}
},
computed: {
options() {
return {
[`v-b-modal.modal-${this.id}`]: "whatever"
}
}
}
}

Angular 5 Component Selector in variable returning string instead of component content

I have some data that contains the selector of a component:
{
label: 'This is a label',
componentSelector: '<app-mycomponent></app-mycomponent>'
}
In my app.component.html
Instead of doing this (for example):
<div>
<app-mycomponent></app-mycomponent>
</div>
I would like to do this:
{{data.componentSelector}}
At the moment when I try this it's returning a string instead of replacing it with the contents of the component.
How can I do this?
You cannot interpolate a component, because it is made up of typescript, html, and css. it has to compile to be displayed, if you think about it, it makes sense.
On another note, even if you could interpolate, it would be a poor Angular Pattern, and could have unexpected outcomes especially in production. Stick to the best practices.

React: Rendering non-existing HTML Element

While reading the React docs, I realized that in JSX, elements starting with a lowercase letter are treated as HTML element. While putting this into practice, I noticed something interesting: When I pass a non-existing, lowercase element, React renders this just fine.
function Foo() {
return (<foo>hello world</foo>);
}
ReactDOM.render(
<Foo />,
document.getElementById('container')
);
This renders like this:
<div id="container">
<foo data-reactroot="">hello world</foo>
</div>
While trying to find an answer on how this is possible, I encountered several projects dealing with Web Components/Custom Elements in React, which confused me a bit.
Does this have something to do with Custom Elements? Will this work in any browser that is supported by React?
No, this has nothing to do with Custom Elements.
It's perfectly fine to create an element which has a tag name that doesn't represent any predefined HTML element. You will get an instance of HTMLUnknownElement:
const myElement = document.createElement('foo');
console.log(myElement.nodeName);
console.log(myElement instanceof HTMLUnknownElement);
Unknown elements don't have special behavior. If you want create a <foo> element which has special behavior, you have to use Custom Elements.
As PeterMader explains, you are creating a custom html element with that syntax. I'll expand on that answer a bit.
First of all it's important to understand that JSX is just a syntactic sugar and that it ultimately transpiles into JavaScript. React elements are created with createElement.
React.createElement(type, props, children);
What's important to note here is that type can be one of the following:
A reference to a React Component (e.g Foo in your example).
A string.
If you are writing React without JSX, then it doesn't matter if you reference a component as foo or as Foo because you have complete control of how you define your variables. In other words, this is plain JavaScript and JSX rules don't apply.
However, if you are using React with JSX, the following rules apply:
type starts with a capital letter = React Component.
type starts with a lowercase letter = HTML element.
In fact, the official documentation says:
When an element type starts with a lowercase letter, it refers to a built-in component like <div> or <span> and results in a string 'div' or 'span' passed to React.createElement. Types that start with a capital letter like <Foo /> compile to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.
We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.
So what about <foo />?
In the event that the type of a React Element doesn't resolve into a React Component and is not a standard HTML, React will still treat it as an HTML element.
To my knowledge, React actually doesn't have any whitelist of "valid" HTML tags, but treats anything starting with lowercase the same way. The result in your browser may differ though, as per PeterMader's response.
As such, this (JSX):
<foo>hello world</foo>
will, in modern browsers, yield (HTML):
<foo>hello world</foo>
which is perfectly fine technically, but probably still not a good idea.

Categories

Resources