I see the 2 terms being used interchangeably a alot.
This has caused me a great deal of confusing, could someone please explain to me the differences?
A component is a set of Elements (as the documentation says):
Note: One might confuse elements with a more widely known concept of
“components”. We will introduce components in the next section.
Elements are what components are “made of”, and we encourage you to
read this section before jumping ahead.
Here I could tell you two quick differences:
The Elements do not have Props or states, they are simply something visual (but you can execute Javascript using {}.
At the time of rendering, the elements are used as any variable, unlike a component that is through the labels, for example:
// This is a component
ReactDOM.render(<Element />, document.getElementById('root'));
// This is an Element
ReactDOM.render(element, document.getElementById('root'));
An element is something assigned to a JSX value:
const foo = <p>My name is foo</p>;
We can render elements into DOM with:
ReactDOM.render(foo, document.getElementById('root'));
You can create a whole app by combining different elements.
const name = "foo";
const greeting = (
<div>
<h1>Hello, {name}</h1>
<p>Welcome!</p>
</div>
);
ReactDOM.render(greeting, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Of course without flexibility and some other advantages like state and life cycle methods it will be sure very hard to write a whole app. So, this is why we have components.
A component is a function which returns JSX element or element compositions.
const Greeting = ( props ) => (
<div>
<h1>Hello, {props.name}</h1>
<p>Welcome!</p>
</div>
);
ReactDOM.render(
<Greeting name={"foo"} />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
So, components actually are functions optionally taking props and return elements. The above code is an example for "functional components". To use state and life cycle methods we have to use "class components".
class Greeting extends React.Component {
state = {
name: "",
}
getName = () => new Promise( resolve =>
setTimeout( () => resolve( "foo" ), 1000 )
);
componentDidMount() {
this.getName().then( name => this.setState( { name } ) );
}
render() {
const { name } = this.state;
return (
<div>
<h1>Hello,
{
!name
? <span> stranger.</span>
: <span> {name}.</span>
}</h1>
<p>Welcome!</p>
</div>
);
}
}
ReactDOM.render(
<Greeting />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Above component waits for one second, then grab the name value and set it to state. Until it finishes our view says "stranger" instead of the grabbed name. This can be possible thanks to life cycle methods and state.
For React, both of those components are the same. They somehow return JSX in the end of the day. Classes are special functions in Javascript, so this is why I said all of the components are "functions". The difference for React, class based components have states and life cycle methods.
Of course components can return other components as well but main difference with a component and element is one of them is just a JSX value, the other one is a function returns elements.
The big difference is, apart from being a function and returning some other elements, of course we have state and life cycle methods for components. If an element is a brick then a component is something like a wall.
Related
I can't really find any documentation for this but is it possible to put ReactDOM.Render() in its own render/function variable?
The reason for this is I want to stream line my codebase and when trying to render multiple components with props etc it gets a little messy.
Example:
ReactDOM.render(
<SuccessErrorModal status={props.status} progress={50} />,
document.getElementById("loading-modal")
);
Desired Result:
const LoadingModal = (props) => {
ReactDOM.render(
<SuccessErrorModal status={props.status} progress={50} />,
document.getElementById("loading-modal")
);
}
<LoadingModal status={true} /> // Calling the ReactDOM.Render()
Create Portal Example (Not working):
const LoadingModal2 = () => {
ReactDOM.createPortal(
<SuccessErrorModal status={true} progress={50} />,
document.getElementById("loading-modal")
);
};
TIA
You can use ReactDOM.createPortal for this.
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
You can get more information here
I want to convert react children to string.
In the below example I am passing div, h2 and p as children to Example in Exampleclass. when I call props.children in Example it returns an array but I need a props.children in the string format so that I can use it in dangerouslySetInnerHTML.
import React, { Component } from "react";
import Example from "./example";
export default class Exampleclass extends Component {
render() {
return (
<div>
<p>in class</p>
<Example> // passing div, h2 and p as children to Example
<div>
<h2>function</h2>
<p>function</p>
</div>
</Example>
</div>
);
}
}
import React from "react";
export default function example(props) {
console.log("child", props.children); // returns array but i need <div><h2>function</h2><p>function</p></div> here
return <div dangerouslySetInnerHTML={{ __html: `${props.children}` }} />; // returns [object Object]
}
It would be difficult to transform children object into some kind of a flat string with a JSX-a-like structure. children is a complex object with a lot of nested fields. You would have to convert it firstly to an array, then iterate over it, probably recursively, pick correct props and so on.
However you could pass your children not as a children, but as a separate prop.
const Child = ({ child }) => {
return <div dangerouslySetInnerHTML={{ __html: child }} />;
};
const App = () => {
const data = `
<div>
<h2>function</h2>
<p>function</p>
</div>
`;
return <Child child={data} />
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Edit: You could, however, use renderToStaticMarkup function, but it will render only pure html (it will compile components into html). In your example you are passing only html elements so I guess it would be okey.
const markup = ReactDOMServer.renderToStaticMarkup(children);
return <div dangerouslySetInnerHTML={{ __html: markup }} />;
react-children-utilities has a function, onlyText, that does this.
It uses React.Children.toArray(children).reduce then recursively loops through children, concatenating a string made up of every child and nested child that is a string or a number, skipping everything else.
Disclaimer: be aware that if your component's children includes components with props or attributes that behave like children when rendered, but aren't actually in the React elements as children, they'll be omitted.
For example, if you're trying to approximate the text that tools like screen readers or search engine bots would read on focusing an element, this approach will skip text in attributes like alt, label or value that such tools might include. It also won't do things like collapse whitespace.
Since onlyText is a pretty simple function, I'd suggest looking at its implementation (linked above) and consider writing your own variant that adds in any other relevant attributes that your use case needs which would otherwise be skipped.
I can define a component like this:
class Welcome extends React.Component {
render() {
return <h1>Hello!</h1>;
}
}
When I want to render this object in the Dom (or rather add it to the virtual DOM) I call
ReactDOM.render(
<Welcome />,
document.getElementById('root')
);
That means that at some point multiple .render() functions are nested inside of each other since we defined return <h1>Hello!</h1>; inside of the .render() function of Welcome.
It also means that I can use the .render() method to render an Object to the DOM and to define a new react object.
This syntax is from the official documentation
Does .render() just render things to the virtual DOM and the nesting is resolved by React internally or is there more behind it?
From Rendering a Component:
(updated to reflect your code)
class Welcome extends React.Component {
render() {
return <h1>Hello!</h1>;
}
}
ReactDOM.render(
<Welcome />,
document.getElementById('root')
);
We call ReactDOM.render() with the <Welcome /> element.
React calls the Welcome component with {} as the props.
Our Welcome component returns a <h1>Hello!</h1> element as the result.
React DOM efficiently updates the DOM to match <h1>Hello</h1>.
It may be beneficial to read up on the React Life Cycle.
To understand render you have to understand how react works internally. To understand this in greater detail I would recoment reading this but here is a quick overview:
Conceptually a react component is a just a function that returns an Object like this:
{
type: 'button',
props: {...}
};
So the render() part of a class component just specifies what part of the component will be returned. The react virtual dom is made up of many of these object nested inside of each other (in props.children). React will start at the top object, turn it into an html node and render it to the dom, then do the same for all of its children etc.
I've just started learning react js from the official site and there is this step in the tutorial in which in order to make a working clock you turn a function into a class. My question is that since it can be done with a much simpler way, why would someone do that?
When you want to get access to all the React.Component features like props and state, life cycle methods, ref and much more, you would need to extend from React.Component.
You can only do that with a class (in ES6)
Edit
Just one thing, you can access to props too declaring a function
This is not true actually, stateless components are just functions that returns jsx. they are normal, regular functions that accepts parameters.
We sometime use the props key word as a parameter just as a habit or convention but you can use whatever key word you want.
Example:
const MyHeader = (myParams) => (
// no props here
<h2>{myParams.value}</h2>
);
class MyApp extends React.Component{
render(){
const {message} = this.props; // i get access to this.props as i extended React.Component
return(<MyHeader value={message} />);
}
}
ReactDOM.render(<MyApp message="Hello!" />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Let's say I have a large HTML document with numerous React Components embedded in parts of it.
For example:
<body>
<h1 id="react-component-1">...</h1>
<p>Static Content</p>
<h2> id="react-component-2">...</h2>
<img src="static-img" />
<p id="react-component-3">...</h3>
</body>
As you can see, there are static elements in-between my dynamic elements. I'd imagine that this situation is common in web sites that are slowly bringing React in to there toolchain.
Right now my application works like this:
function renderPage(data) {
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-1"));
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-2"));
ReactDOM.render(<Component {...data} />, document.getElementById("react-component-3"));
}
renderPage() is called upon the success of an ajax request. This makes my components update as intended, and it seems pretty performant.
However, it would be much nicer if I had a root React component that handled the state of the application, and pushed down changes to data as props.
I can't make a root component though because not everything on my page is dynamic, I need to preserve the static content in-between the React components.
I would love to be able to do something like this though:
class Root extends React.Component {
constructor(props) {
super(props);
this.data = {...};
}
render() {
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-1"));
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-2"));
ReactDOM.render(<Component {...this.state.data} />, document.getElementById("react-component-3"));
}
return false;
}
Is it possible to use React this way? At first I unsure of how it would be possible, because ReactDOM expects an element to render components in to, which would clear out my static content when I render my root component. Now I am thinking I could just do new Root(), but I have yet to test this.
Another option that I just thought of was keeping the renderPage() function and calling it ONCE instead of every time AJAX is loaded. Each component would then listen for a custom event that is fired on the AJAX success, which contains the new data. This seems slower though... And I might as well use Redux for the application state.
You shouldn't use the render method of a React component to call ReactDOM.render the way you do it in your example Root component. The render method of a component can return either a valid React element (for example, <div />) or null and is not supposed to do any mutations, such as modifying the DOM, etc. If a React component needs to do some DOM mutations, it should do it from lifecycle hooks such as ComponentDidMount or ComponentDidUpdate.
To answer you question, it depends whether your static content, can be included in a React component or not.
If you can, which would be ideal, you can refactor your code to have a Root component like so :
class Root extends React.Component {
render() {
return (
<Component data={ this.props.data } />
<p>Static Content</p>
<Component data={ this.props.data } />
<img src="static-img" />
<Component data={ this.props.data } />
);
}
}
and to have one call to ReactDOM.render :
ReactDOM.render(<Root data={ data } />, document.getElementById('my-react-mounting-point'));
If you cannot, that is if you need to have different React render trees, your current approach is fine. If you do this, though, be careful to call ReactDOM.unmountComponentAtNode when you do not need the component anymore, or you might face memory leak issues. This article from React's blog has several nice tips about the precautions to use when having various render trees + a ReactComponentRenderer boilerplate to avoid common pitfalls.