Render function in reactjs - javascript

Quick question. I'm learning react js.
When we create a component, we provide in the render function the html template of the component to render.
So far I have only seen small components with very small pieces of html, but I was just wondering what happen if we have a component with a huge html template, is there any way to provide the path to a separate html file? Or we are forced to write all the html directly inside the render function? Thanks!

You should always write it in the render function. You're not writing HTML in there, you're writing JSX, which is compiled into Javascript. Something like <div className="test"> is converted into React.createElement("div", {className: 'test'});.
You shouldn't have an issue of size as long as you break down large components into a composition of many smaller components. You can include other components by including them in your render function, like this: <SomeComponent someProp="someVal" />.

You can split your render function to the bunch of good-named methods like a partials in old plain html-templates. It's useful to make complex react-components, because you will remove big unreadable html-part from your code.
For example, here is some pseudo-code described this approach:
class NavBar extends React.Component {
// Render user name and links on profile and logout
renderUser() {
if (!user) return;
return <div>{user.name}</div>;
}
// Render list with nav-bar items if they exists
renderNavBarItems() {
if (!user) return;
return <ul>{this.items.map((i) <li><a href={i.link}>{i.name}</a></li>)}</ul>;
}
render() {
return (<div className="nav-bar">
{this.renderNavBarItems()}
{this.renderUser()}
</div>);
}
}

Related

How to make react know my separately loaded HTML?

I want to separate JavaScript and HTML in react. I'm not a big fan of their philosophy of mixing them together.
So, basically I created my component .js files. For example teachersList.js and this is my code:
class Teacher extends React.Component {
constructor() {
super();
this.state = { teachersCount: 20, html: <div>loading</div> }
}
componentDidMount() {
var that = this;
setTimeout(function () {
that.setState({ html: <div> dynamic HTML is loaded: {that.state.teachersCount}</div> })
}, 2000);
}
render() {
return (
<div >
<div dangerouslySetInnerHTML={{ __html: this.state.html }}></div>
</div>
)
}
}
And it works just fine. However, when I change the componentDidMount function to load HTML from server, it breaks:
componentDidMount() {
var that = this;
$.get("/teacher/list.html", function (data) {
that.setState({ html: data })
})
}
What should I do?
Your approach to use real HTML together with React just doesn't work, conceptionally.
(I think it is pretty save to say that here, even though there are some ways to inject HTML into React)
It is not possible (conceptionally) to use something like HTML-templates with React. The only solution would be to not use React.
You should decide if you want to write HTML or React, not both.
I think it is not precisely true to say that "React mixes HTML and Javascript", it would be better to understand React as an abstraction of HTML and JS. There is no real HTML in React, React is kind of a separate language, you just write React instead of HTML. The code that looks like HTML is not real HTML, it is JSX, which is Javascript hidden behind a special syntax that looks like HTML, for convenience.
So, if you decide to use React, then don't write HTML at all (but write JSX). If you want HTML, then don't use React.
separating logic and view
You say you don't like mixing HTML and Javascript, but there is no HTML, so what do we actually want to not-mix ? I think it makes sense to separate page-structure and app-structure. E.g. you may go for separating into different components / files:
HTML-Tag-JSX (like <div className="...">...), which will be shown in the resulting HTML code pretty much the same as you write it in JSX, and
React components (like <MainContent store={ store } />), which have pretty much nothing to do with HTML code at all.

How to create inject React components from XML

Imagine you made a web framework that helps you quickly make blogs for clients. For the sake of this post, its the same blog template everytime, what changes is the content. You're React app is a simple structure of the following [where the Content state is just changing each time]
<App>
<Navigation/>
<Content/>
</App>
What makes the framework is you have XML files which contain the HTML. Each XML file represents one blog post. The app pulls all the HTML from the XML files, and puts it into the state of the App in a "blog posts" array. Depending on the state of the app, a specific entry in the array will be displayed in Content...
Content's state has a field called "html" which is what holds the HTML to be injected in string form. [you have to use dangerouslySetInnerHTML]
This concept works fine, and I have a version of it now. However, imagine you have a React components that you want to add to each blog post. Say you want to add the component into a specific blog post in a specific section. You want to add props to it and such. Now this goes out the window with dangerouslySetInnerHTML
This is where I am stuck trying to find the best direction to go. The only thought I have now is the following:
Since you would now be writing JSX in the XML, just make each blog post its own component. You would have ...etc and then if this.state.currentPost === 1 then display BlogPost1 and likewise. Yet you would have to have a huge block of if-statements depending on how many blogposts you have, and its not ideal to have to add everytime you have a new blogpost
When I read the title of your question I got curious and found this library to parse XML into React components: xml-to-react. But that's not what you are asking for.
As you want to use components in the middle of you string of HTML, I'll suggest: react-remarkable. This component compiles its children (a string with markdown/html/react) into react nodes.
Example from its docs:
var React = require('react');
var Markdown = require('react-remarkable');
var MyComponent = React.createClass({
render() {
return (
<div>
{/* Pass Markdown source to the `source` prop */}
<Markdown source="**Markdown is awesome!**" />
{/* Or pass it as children */}
{/* You can nest React components, too */}
<Markdown>{`
## Reasons React is great
1. Server-side rendering
2. This totally works:
<SomeOtherAmazingComponent />
Pretty neat!
`}</Markdown>
</div>
);
}
});

is there such a thing as JSX 'partials'?

I work mainly with Handlebars JS now, but I am looking at JSX. Is there a JSX equivalent to Handlebars partials? I want to know if I can create small bits of markup that I can reuse in several different JSX views.
It doesn't provide partials. Some things about React:
React doesn't provide any notion of partials. The fundamental, atomic unit of React is the component.
Instead of passing a partial, you'd create a component or components and re-use those. Even better than a partial because it's a function, so it's encapsulated and testable!
If the markup is small, it should probably either be moved up into a parent component or down into a simpler one
Generally, my rule of thumb is that components should follow the principle of single responsibility or separation of concerns. If something doesn't seem to fit into a component, you've likely got problems in the other two components and could reconsider them, too :)
Another couple rules of thumb to go by when thinking about components:
code smells should usually end up as components (repeating something over and over again, etc.)
components are usually either presentational or containerized. The latter have roles in the props/state tree for an app (you never "see them")
refactor things into components as you need to; don't start out encapsulating everything, because you may have prematurely refactored and created more problems for yourself
the most reusable and decoupled components are like the best functions or objects: clean, flexible, testable, and they do address a single concern
at the same time, don't go crazy and turn everything into a component. i.e. you don't (usually) want:
<Letter>R</Letter><Letter>e</Letter><Letter>a</Letter><Letter>c</Letter><Letter>t</Letter>
Here's an incredibly simple example:
'use strict';
const OuterComponent = React.createClass({
render() {
return (
<div>Outer{this.props.children}</div>
);
}
});
const ReusableComponent = React.createClass({
render() {
return (
<div>Am I reusable? {this.props.reusable && 'Yeah!' }</div>
);
}
});
ReactDOM.render(
<OuterComponent>
<ReusableComponent reusable={true}/>
</OuterComponent>,
document.getElementById('container')
);
Will render:
OuterComponent
Am I reusable? Yeah!
Note, though, that using creatClass provides you more than you might need if you're not working with mutable state (which is provided to you within the component via this.state), you can easily use what are sometimes called "stateless functional components" (because they are, well, stateless and returned by functions). These could easily be arrow functions implicitly returning the JSX (which is essentially just React.createElement() generator)
const OuterComponent = (props) => <div>Outer{this.props.children}</div>;
const ReusableComponent = (props) => <div>Am I reusable? {this.props.reusable && 'Yeah!' }</div>;
ReactDOM.render(
<OuterComponent>
<ReusableComponent reusable={true}/>
</OuterComponent>,
document.getElementById('container')
);
Just create a component for that. Components can be as simple or as complex as you want them to be.
Example:
function Badge(props) {
return <span className="badge">{props.counter}</span>
}
With a corresponding .badge CSS class, this could be a very simply component that renders as a red circle with a number, and is used as <Badge counter={42} />.

React: Bubbling up click events on nested components

I'm creating a react file tree, and I have the tree setup as a React component. The tree can take a contents prop that is an array of either strings, or other <Tree /> components (this enables the nested file structure UI). These tree components can be nested indefinitely.
I need to register a click event on the children of the nested tree components, but I'm having trouble getting it to work beyond the first level of nesting. A simplified example of what I'm dealing with:
//In App - the top level component
const App = React.createClass({
_handleChildClick () {
console.log("this is where all child clicks should be handled");
},
render () {
return (
<Tree
handleChildClick={this._handleChildClick}
contents={[
<Tree />
]}
/>
);
}
});
//And in the tree component
<div onClick={this.props.handleChildClick}></div>
If you want to see more detail - here's the github repo.
I tried researching this question and saw people using {...this.props} but I'm not sure if that applies to my scenario - if it does, I couldn't get it to work.
Thanks for any help on this.
The reason why the click handling does not work beyond the first level is because your second level Tree component (the one inside the contents array) does not get the appropriate prop handleChildClick passed in. (BTW I think the convention is to call the prop onChildClick while the handler function is called handleChildClick - but I digress.)
Do I understand correctly that you actually want to inform each layer from the clicked component up to the top? For this to happen, you need to extend the props of the tree component that is inside the contents array - it needs to receive the click handler of its parent component. Of course, you cannot write this down statically, so it needs to be done dynamically:
Your Tree component, before actually rendering its children, should extend each of them with the component's click handler, which can be done using the function React.cloneElement (see API documentation and a more detailed discussion). Directly applying this to your component makes things a bit messy, because you are passing the component's children in a prop, so you need to figure out which prop to modify. A bit of a different layout would help you quite a lot here:
<Tree handleChildClick={this._handleChildClick}>
<Tree />
</Tree>
looks nicer IMHO and makes the structure much clearer. You can access the inner components via this.props.children, and cloneElement will be much simpler to use.
So, in your Tree component, you could have a render method like this:
render () {
const newChildren = this.props.children.map(child =>
React.cloneElement(child, {onChildClick: this._handleChildClick}));
return (
<div>{newChildren}</div>
);
}
Please note that this code will not work if you have a mixture of strings and Tree components, therefore my third and last suggestion would be to wrap those strings into a very thin component to allow for easier handling. Alternatively, you can of course do a type comparison inside the map.

What's the difference between using a stateless functional component versus calling a method?

I'm trying to understand stateless components and what the difference is between these examples:
class App {
render() {
return (
<div>
{this.renderAFunction('hello')}
</div>
);
}
renderAFunction(text) {
return (
<p>{text}</p>
);
}
}
and this:
class App {
render() {
return(
<div>
<RenderAFunction text='hello'/>
</div>
);
}
}
const RenderAFunction = ({text}) => (
<p>{text}</p>
);
Or if there is any difference at all?
Functionally, there is absolutely no difference. Both end up rendering a paragraph element, but there are other aspects to consider. There are three points to make (in my opinion) when examining both methods:
Reusability: You have to understand to separate components when you need to. If renderAFunction is just meant to generate some JSX based on, for example, an API request, then it's fine being in a method. But if you want to reuse it somewhere else, then separate it into it's own component. A huge part of React is component reusability and getting rid of code duplication. Separating the method into it's own component would be imperative to accomplish this.
Purpose: There are reason to use stateless function components and reasons not to. The whole point of stateless functional components is to not have state and be presentational. If you need to do something that involves the React lifecycle or internal state, keep it as a method, or new class depending on if you want it reusable.
Performance: Using a stateless functional component would be less efficient. This is because it's a component, not just some JSX returned from a method. As of right now, the React team plans on making some optimizations for stateless functional components because they do not contain state and are merely presentational, but this probably won't happen until after React Fiber is done and thus your stateless functional component has no optimizations versus a regular full-fledged class component. That makes it incredibly inefficient versus a method returning some JSX, especially if it's just used once in another component.
A good rule of thumb is to ask yourself, do I need it anywhere else? If not, then keep it in a method. If you don't need it anywhere else, separating the JSX into a separate component would have worse performance and wouldn't follow React's core principles.
If you are going to need it somewhere else, then separate the component so you follow React's concept of reusability.
Your App's render function will be translated into following JS code for your first example:
render() {
return React.createElement(
'div',
null,
this.renderAFunction('hello')
);
}
And the following one for the second one:
render() {
return React.createElement(
'div',
null,
React.createElement(RenderAFunction, { text: 'hello' })
);
}
While they both looks almost the same, there is one significant difference: laziness. React will execute RenderAFunction body only in case it gonna be mounted to the DOM hierarchy.
It is insignificant is your case, but imaging following example:
const LazyApp = () => {
const heavy = <div><HeavyStuff /></div>
// ...
return <div>done it</div>
}
const HardWorkingApp = () => {
const heavy = <div>{HeavyStuff()}</div>
// ...
return <div>done it</div>
}
const HeavyStuff = () => {
// ... do heavy rendering here
}
Lazy app will not perform any heavy stuff at all. Maybe it is not very clear from that synthetic example why one would do anything like that at all. But there are real-world examples out there, when something conceptually similar (creating Components without rendering them) is happening.
Basically, both will serve the same purpose. But the real advantage of creating a component is its reusability.
If you have to render that particular piece of jsx just for this component. Then, there is no need to create a separate component.

Categories