Using loop outside of render function in React.js - javascript

I am building a checkers game using React.js, and I would like to create a loop that renders my "Square" component 64 times in order to create my "Board" component. I am able to render the Square components correctly when running the .map function inside of the render function. However, I don't like having the .map function taking place inside the render function, and would like to call a separate function that does the same thing inside the render function. When I move the .map function into the renderSquares function, the squares do not get rendered. Can someone explain what I'm missing here? Thanks.
import React, { Component } from "react";
import Square from "./Square";
class Board extends Component{
constructor(){
super()
this.state = {
myArray: Array(64).fill(null),
checked: false
}
console.log(this.state.checked)
}
renderSquares(){
this.state.myArray.map(function(obj, key){
return <Square key={key} checked={this.state.checked} />
}, this)
}
render(){
return(
<div className="wrapper">
{this.renderSquares()}
</div>
)
}
}
export default Board;

Your renderSquares is missing a return.
return this.state.myArray.map etc.

When you call this.renderSquares() inside the render function, the keyword this will not refer to the Board component inside the renderSquares() function. One way to fix that is to use bind:
{this.renderSquares.bind(this)}
I much prefer another way -- using the arrow function:
Instead of using renderSquares(), define it using:
renderSquares = () => { ... }
That way, the keyword this will be referring correctly to the Board component. Note that this approach might not work if you don't have the right babel presets installed (I always make sure to use the following babel presets: react, es2015, and stage-1)

Related

Rendering a component in JSX vs via function

When using React, what is the difference (and when should each method be applied) when rendering a component?
Does this impact the component lifecycle in any way? Or impact how hooks are run in the component?
Method 1:
class App extends React.Component {
...
function getComponent() {
return <Component />
}
render() {
return this.getComponent()
}
}
Method 2:
class App extends React.Component {
...
render() {
return <Component />
}
}
(Note: The OP has now changed the question, it used to have return {this.getComponent()} in Method 1.)
render in Method 1 is incorrect (well, it was before the edit), it should be:
render() {
return this.getComponent() // No {} wrapper
}
You need the {} within a JSX context, but you're not in a JSX context there. For instance, if you wanted to wrap what this.getComponent returned in a div, you'd use the JSX expression to define the div's children within the JSX defining the div:
render() {
return <div>{this.getComponent()}</div>
}
With the {} sorted out, whether you use Method 1 or Method 2 is up to you. If you have substantial parts of the render that you want to move into their own functions, that's fine. For instance:
render() {
return (
<div>
{this.getHeader()}
{this.getBody()}
{this.getFooter()}
</div>
);
}
...although I think I'd probably argue at that point that without a good counter-argument, the header, body, and footer should probably be components (perhaps function components). But the occasional helper function call like that is fine.
Does this impact the component lifecycle in anyway?
No. It's just a function call within render.
There is no real difference between both. I'd personally use only one render() method as much as possible, then when the method gets too big, extract parts of it into their own method.
I have found this great article by Kent C. Dodds. An extract of the article is:
React doesn't know the difference between us calling a function in our JSX and inlining it. So it cannot associate anything to the Counter function, because it's not being rendered like a component.
This is why you need to use JSX (or React.createElement) when rendering components rather than simply calling the function. That way, any hooks that are used can be registered with the instance of the component that React creates.
With this in mind, it sounds like it's better to use JSX when rendering a component that uses hooks.

Functions inside and outside render()

I just begun to learn React and JavaScript in general. After I read the documentation and tutorials, I took a look at example projects and try to sort out what I didn't get yet.
And then I saw that there are functions that are defined inside the render()functions, and some that are outside of the render() function.
E.g. for outside of render():
handleClick(e) {
e.preventDefault();
e.target.parentElement.classList.toggle('open');
}
and inside render()...
const divider = (divider, key) => {
const classes = classNames( 'divider', divider.class);
return (<li key={key} className={ classes }></li>);
};
Why do they look so different and why would you like to have some functions inside and some outside of render()?
EDIT:
Another example for a function outside of render():
hideMobile() {
if (document.body.classList.contains('sidebar-mobile-show')) {
document.body.classList.toggle('sidebar-mobile-show')
}
}
EDIT2: In another thread someone answered that, if the logic behind the function is heavy, it should be outside of render(). But why would you like to have function inside render() anyways?
render() is called everytime the state change. So every function that is kept inside render function will be created as a new function each time the state change. Which means that divider will be created newly every time react re-renders.
handleClick is a normal object function.
Functions written inside render function are usually those dealing with rerendering of components.
From example on official site:
First, if we want to build a Clock in the beginning, this how we tried to make a component that is object-oriented, maintainable factor with a stateless function object.
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
quote from doc
to make the Clock component truly reusable and encapsulated. It will
set up its own timer and update itself every second.
...
Ideally we want to write this once and have the Clock update itself...
So here is the spirit of React, we want to convert this function object to a class, which could maintain itself, so now we involve render() in, more specifically we involve stateful component in:
Add a single empty method to it called render()
...
Clock is now defined as a class rather than a function.
Then we get:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
this.clockCore = this.clockCore.bind(this);
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
tick() {
this.setState({
date: new Date()
});
}
clockCore() {
return (<div>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>);
}
render() {
return this.clockCore();
}
}
As you known, render() be triggered again an again if the state of component need to be refreshed by setState().
Update
In my opinion, it's unnecessary to define the function in render().
I have made a little revisions to the original example above to show that.
From example you provided, the usage of divider may be like:
const divider = (divider, key) => {
const classes = classNames( 'divider', divider.class);
return (<li key={key} className={ classes }></li>);
};
return (<ul>{this.state.dividerList?
this.state.dividerList.forEach(divider) : null}</ul>);
I think the reason of this is just for maintainability, someone may want all DOM creating code inside the render() for easy tracing when DOM structure returned is really complicated (and arrow function is lightweight), but as I said it's subjective, it really could be defined outside.
In this kind of case, I used to do below instead, and it seems what you provided is more elegant, but if you defined that function outside of render(), things become distractive to me.
let dividers = [];
if (this.state.dividerList) {
this.state.dividerList.forEach((divider, key) => {
let classes = classNames( 'divider', divider.class);
dividers.push((<li key={key} className={ classes }></li>));
});
}
return (<ul>{dividers}</ul>);
So another function you provided which aims at DOM manipulations feature is totally proper and well to be defined outside.
Besides that, handleClick is a function created and accessible for every Object/Component and divide is a locally scoped function, their functionality can be pretty much the same. However, divider will be created as new function on every render which might have later performance implications, while handleClick is created once for a defined component (Object).

Integrating and rendering react-swipe-cards

I am very noob with reactJs, in fact I just finished this course and am struggling with some concepts here.
I am willing to create an app for people to express their preferences with regards of subjects for a newsletter, and have grabbed a very comprehensive list of topics (2k+) and wanna make some fun way to select them, so I think that something along the lines of Tinder swipeable cards would be a perfect fit, so I am trying to implement this react module functionality into my App.
But it is not showing up anything.
I just created a Repo, in which I had a few tries with no luck.
Basically, the example provided in the module documentation says that it should start by
const data = ['Alexandre', 'Thomas', 'Lucien', 'Raphael', 'Donatello', 'Michelangelo', 'Leonardo']
const Wrapper = () => {
return (
<Cards onEnd={console.log("action('end')")} className='master-root'>
{data.map(item =>
<Card
onSwipeLeft={console.log("action('swipe left')")}
onSwipeRight={console.log("action('swipe right')")}>
<h2>{item}</h2>
</Card>
)}
</Cards>
)
}
But I am completely lost with it, I supposed that it should provide me with a React Component <Something />, but instead it generate something in the lines of a function, that returns a div, which looks a lot with a component, but I have no idea about how integrate into this example.
Note: In the repo graph, I noticed that there is another developer that made some adjustments to make it compatible with react 16.xx.beta, I'v tried it also, no lucky also.
I am almost sure, that there are some concepts I am missing here, so, any reference is more than welcome, also.
What you are looking for is a functional stateless component, the below code
const Wrapper = () => {
return (
<Cards onEnd={console.log("action('end')")} className='master-root'>
{data.map(item =>
<Card
key={item}
onSwipeLeft={() => {console.log("action('swipe left')")}}
onSwipeRight={() => {console.log("action('swipe right')")}}>
<h2>{item}</h2>
</Card>
)}
</Cards>
)
}
is a functional component.
According to documentation
Functional and Class Components
The simplest way to define a component is to write a JavaScript
function:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
This function is a valid React component because it accepts a single
“props” (which stands for properties) object argument with data and
returns a React element. We call such components “functional” because
they are literally JavaScript functions.
The way to render a function component is just like you would render a normal React component
<Wrapper {...props} /> // {...props} is a spread operator syntax to just pass all the props down to wrapper you can pass selected props too
Also react-swipe-card doesn't provide you Wrapper functional component, it provides you components like Cards and Card which you used to render the card view in the Wrapper Component
import Cards, { Card } from 'react-swipe-card'
Now in your case it would look like
export default class MyCards extends Component {
render() {
return <Wrapper />;
}
}
However since you don't have a state and also you are not using lifecycle functions you could simple write the above MyCards Component as
export const MyCards= () => {
return <Wrapper />;
}
I however assume that you would eventually be writing some of the logic there and hence keep it a stateful React component. I have also include the logic whereby you would handle the state change on left or write swipe.
Check a working DEMO
P.S. I a recommendation to go through the React docs thoroughly as they have explained the concepts really well
If I understand you question as suppose. It look you have some small mistake. I download the repo and run you test on React 15.4.2
Your Card component call:
<Card
onSwipeLeft={console.log("action('swipe left')")}
onSwipeRight={console.log("action('swipe right')")}>
<h2>{item}</h2>
</Card>
My Card component call:
<Card
key={item}
onSwipeLeft={()=>{console.log("action('swipe left')")}}
onSwipeRight={() => {console.log("action('swipe right')")}}>
<h2>{item}</h2>
</Card>
We need to create scope for events handler that is why one of the solution is a arrow function. They aren’t just syntactic sugar around anonymous functions though. An arrow function does not have its own context and will instead use the same this as the context in which it was defined. Here is more detail handle-events-in-react-with-arrow-functions
Also on the MyCards you are returning something like (your code)
export default class MyCards extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return Wrapper;
// return (
// <div>
// <p>Something</p>
// {Wrapper();}
// </div>
// );
}
}
But you should return a component and the way is return it have to be
export default class MyCards extends Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return <Wrapper/>
}
}
Suggestion: If you are not going to have any state in the MyCards component you can make it a functional Component
The current top answer is correct and great about the concept of the functional component. You are actually creating a High Order Component.
However I feel your repo can actually be fixed by just making this change:
render() {
return Wrapper();
}
See that I actually executed the Wrapper function in order to get the Component as a result, otherwise you are rendering a function and not a Component.
You can refactor your code to actually extend a React.Component, and I actually recommend this as HOC are better used for another type of objective, like decorators.
See here, the only thing I changed is that: https://codesandbox.io/s/xp6pzpyoq

Closures in React

Is it ok use closures in react, for event handlers?
For example, i have some function and a lot of menu in navigation
and in navigation component i use something like this:
handleMenuClick(path) {
return () => router.goTo(path)
}
...
<MenuItem
handleTouchTap={this.handleMenuClick('/home')}
>
or i should prefer just arrow function?
<MenuItem
handleTouchTap={() => router.goTo('/home')}
>
first variant really make code cleaner, but i'm worried about performance with a large number of such elements
Both should be avoided.
While they'll both work, they both have the same weakness that they'll cause unnecessary renders because the function is being created dynamically, and will thus present as a different object.
Instead of either of those, you want to create your functions in a static way and then pass them in. For something like your MenuItem, it should just get the string for the path and then have the code to do the routing inside. If it needs the router, you should pass that in instead.
The function should then be a pre-bind-ed function (usually in the constructor) and just passed in.
export class MenuItem extends React.Component {
constructor() {
this.handleClick = () => this.props.router.go(this.props.path);
}
render() {
return (
<Button onClick={ this.handleClick }>Go to link</Button>
);
}
}
You can use an arrow function in the constructor. That way it isn't recreated every render function, and thus you avoid unnecessary renders. That pattern works well for single-line simple functions. For more complex functions, you can also create them as a separate function, then bind it in the constructor.
export class MenuItem extends React.Component {
handleClick() {
this.props.router.go(this.props.path);
}
constructor() {
this.handleClick = this.handleClick.bind(this);
}
render() { /* same as above */ }
}
The point of this is that the handler is the same function every time. If it was different (which both methods you describe above would be), then React would do unnecessary re-renders of the object because it would be a different function every time.
Here are two articles which go into more details:
https://ryanfunduk.com/articles/never-bind-in-render/
https://daveceddia.com/avoid-bind-when-passing-props/
when you define a new method inside a react component (Object) as we know functions are object in javascript.
let reactComponent={
addition: function(){ //some task ...},
render: function(){},
componentWillMount : function(){},
}
so, every new method should be bind with in the object using bind, but render() is already defined so we don't do
this.render = this.render.bind(this)
for each new function, except react lifecycle methods are needed to be added and hence, we call the object (constructor function) methods using this.method().

How I can render react components without jsx format?

I try to make my "smart" popup component, which can open inside itself some components, but my realization isn't good, because it doesn't work.
I use redux approach for creating popup and action of opening my popup is able to get name of any component for rendering before popup will be open;
But I've some problem, after getting parameter, in our case it's nameOfComponent, I need to choose and render component with name nameOfComponent.
And my question now, how do It can render component from array?
// He's my components
import Login from '../Login/login.js';
import Logout from '../Logout/logout.js';
const popupContent = {
Login : Login,
logout: Logout
};
// My component
class Popup extends Component {
componentDidUpdate () {
// for example
const nameOfComponent = "Login";
this.body = this.setBodyPopup(nameOfComponent);
return true;
}
setBodyPopup(property){
return popupContent[property];
}
render() {
// I want to render some element from popupContent here
<div>
// <this.body /> // it's jsx format
{this.body}
</div>
}
}
I added working example here JSfiddle ReactJS
You dont have to use JSX. If you do, right way to do this is to use factory. You can also render regular HTML in the render method, as well as to use vanilla javascript in your code using curly braces.
Also to get I would recommend mapping and iterating through all your items in array and render them one by one in the render method
see example below:
var Login = React.createClass({
render: function() {
return <div>{this.props.name}, logged in</div>;
}
});
// React with JSX
ReactDOM.render(<Login name="John" />,
document.getElementById('containerJSX'));
// React without JSX
var Login = React.createFactory(Login);
ReactDOM.render(Login({ name: 'Tim' }),
document.getElementById('containerNoJSX'));
As commentators suggest, you might want to specify this.body either in constructor or within the render method itself.
However, if I understand your intention correctly, you could just use this.props.children instead.
E.g.
<Popup><MyInnerComponent></Popup>
and in Popup render method
render() {
<div>
{this.props.children}
</div>
}
React actually allows you to use variables with JSX syntax to instantiate components. You should actually be able to call <this.body /> and have it work; however yours will not because you do not define this.body until the componentDidUpdate method, which means it will be undefined for the first render and break everything. I would suggest using local component state for this instead of this.body and making sure it is defined from the start.
At the very least, instantiate this.body in a constructor to some value:
constructor(props) {
super(props);
this.body = 'Login';
}
You can use <this.body /> to render the component, as long as this.body has an actual value. Perhaps you just need:
render() {
return <div>
{this.body ? <this.body /> : null}
</div>
}
With the example you gave, though, you can just put the contents of your componentDidMount in the constructor instead, because the constructor is invoked before the first render pass.
I think you are looking at something like dangerouslySetInnerHtml.
<div dangerouslySetInnerHTML={this.body} />

Categories

Resources