render array of object into a <li> in react.js - javascript

I read an article and the author critic below code, I wonder what's wrong with it. I was starting to learn React, too bad the author did not point out what's his problem with the code below. I tested the code below, it's running fine.
import React from 'react';
import './App.css';
const TodoItems = React.createClass({
getInitialState() {
return {
items : [
{id:1,name:"Gym"},
{id:2,name:"Jump"},
{id:3,name:"Racing"}
]
}
},
renderItem(){
return(
<ul>
{this.state.items.map((item,i) =>
<li key={i}>item.name</li>
)}
</ul>
)
},
render(){
return (
<renderItem />
)
}
})
ReactDOM.render(<TodoItems />,document.getElementById('app'));

The method renderItem should be outside as a functional or stateless component:
const RenderItem = (props) => {
return(
<ul>
{props.items.map((item,i) =>
<li key={i}>item.name</li>
)}
</ul>
)
};
The render method of the parent component should be:
render(){
return (
<RenderItem items={this.state.items} />
)
}
This is the standard way that we write React components. It causes maintainability issues when you write it that way.

In short, you code will not ensure component re-usability.
With React, you'll get the most of re-usability. In the above code, I can see that you are trying to render the items in the state in the function renderItem(). The need of using functions in any language is also to ensure re-usability. So, in React when you when you want to re-use a part which will return a HTML elements, make it as a separate component.
See the following fiddle
https://jsfiddle.net/Pranesh456/b6v6fxrj/1/
Here, I made the renderItem() as a separate component <RenderItem> which can be reused in n number of other components..

Related

React.JS vs Vanilla JS, performance: (28x faster)

I'm starting to develop with React, I went through React Native first, so I'm a bit used to their ideas.
What's my problem with these structures:?
Performance, speed.
I wonder since then.
An example ? I realized when presented some mobile animations, they performed horrible when used in synchronous modes.
Maybe I didn't know the framework in an advanced way to understand it and extract its potential, but as you know, using it leaves you in the dark in some parts.
I'll leave here an example of how I reproduced this difference in speed between 'Vanilla JS' and React.JS.
React.JS
I'm just using an API to get all countries (250) and display them after the call.
This is the code: Main-> Container-> List-> Country,
I also used Styled Components, FontAwasome.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import './api.js'
import styled from "styled-components";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { library } from "#fortawesome/fontawesome-svg-core";
import { faUser } from "#fortawesome/free-solid-svg-icons";
class Country extends React.Component {
clickChild = () => {
this.props.clicked(this.props.name)
}
render() {
return (
<Box onClick={this.clickChild} className="content">
<ImageBox flag={this.props.flag}>
<Icon num={this.props.num}><FontAwesomeIcon icon="user"/></Icon>
</ImageBox>
</Box>
);
}
}
class Lista extends React.Component {
constructor(props) {
super(props)
this.state = {lista:[]}
}
componentDidMount(){
let lista_temp = []
console.log("Iniciando requisição !")
fetch("https://restcountries.eu/rest/v2/all")
.then(resp => resp.json())
.then((json_data)=>{
for(var i=0;i<json_data.length;i++){
var population = (json_data[i].population).toLocaleString(undefined,{minimumFractionDigits: 0})
lista_temp.push({flag:json_data[i].flag,name:json_data[i].translations.br,num:population})
}
this.setState({lista:lista_temp})
console.log("Concluído !")
});
}
click(name){
window.open('https://pt.wikipedia.org/wiki/'+name,"_blank")
}
render() {
return (
<div className="lista">
{this.state.lista.map((tile,index) => (
<Country key={index} flag={tile.flag} name={tile.name} num={tile.num} clicked={this.click}/>
))}
</div>
);
}
}
class Container extends React.Component {
render() {
return (
<div className="container">
<div className="main_contant">
<Lista/>
</div>
</div>
);
}
}
class Main extends React.Component {
render() {
return (
<Container/>
);
}
}
// ========================================
ReactDOM.render(
<Main />,
document.getElementById('root')
);
When we look at the List component, do we have the use of Hooks? I can't say exactly what happens with this use, it seems to be the cause of the problems. Hooks are theoretically not supported in class components.
When we look at its usage, notice that I refresh the list after the entire API is complete, but I can make it much worse by calling setState on each loop item.
this.setState ({list: [... this.state.lista, {flag: json_data [i] .flag, name: json_data [i] .translations.br, num: population}]})
Here are the comparisons in terms of numbers.
A note: I won't put the Vanilla code (I'll leave a link if you like), but I'll show you its interface. It has a lot more interaction than React.
In React there is just one click of the event. In vanilla we have animations, autocomplete, consumption of another API and other events. And basically it's an '.append' html for each item consumed by the API.
I don't know why, but I changed the code to post here, and I realized there was an improvement, I don't understand, before it was between 6s - 9s, now it's 4s.
Vanilla
React and broken instruction;
What's wrong with my learning from this framework, any direction?
https://github.com/ricardosc12/stack_ask

Problem with loading JSON file in React Router

I try to get only the name's region in this API link but it shows me errors in the properties of the setState. Syntax problem or something else?
By the way: Why I use this case, map function? For future purposes.
Thanks!
App Js :
import React from 'react';
import './App.css';
import Region from './region';
import {BrowserRouter,Switch,Route} from "react-router-dom";
function App() {
return (
<div className="App">
<BrowserRouter>
<Switch>
<Route exact path = "/" component={Region}/>
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
the component:
import React, { Component } from "react";
class Region extends Component {
constructor (props) {
super (props)
this.state = {
items:[],
isLoad:false
}
}
ComponentDidMount () {
fetch("https://restcountries.eu/rest/v2/region/europe").then(res=>res.json()).then(JSON=> {
this.setState ({
isLoad = true,
items = JSON,
})
})
}
render () {
let {isLoad,items} = this.state;
if(!isLoad) {
return <div>Loading...</div>
}
else {
return <div>
<ul>
{items.map(items=>(
<li key={items.name}> </li>
))}
</ul>
</div>
}
}
}
export default Region;
json file: https://restcountries.eu/rest/v2/region/europe
The reason behind .map() is you get an opportunity to manipulate your array elements by accessing each elements and returning a different way, structure. In React case it helps to render proper JSX elements for render() method. Suggested read Lists and Keys from React's official documentation.
Read from Array.prototype.map() documentation:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
First issue is wrongly passed properties to setState(), please note that I'm using : instead of =. Try to change as the following:
this.setState({
isLoad: true,
items: JSON,
});
Additionally you can try the following - you had the same name for current element as the array itself - it just better to have different name:
return <div>
<ul>
{items && items.map(e => <li key={e.name}> {e.name} </li>)}
</ul>
</div>
I hope that helps!

How to pass this.props.children using hooks in react

this is my first time to create a react application.
I wanted to pass buttons from index.js to table component that uses hooks.
Declaration:
const testButton = () => {
return (
<React.Fragment>
<button>Test1</button>
<button>Test2</button>
<button>Test3</button>
<button>Test4</button>
<button>Test5</button>
</React.Fragment>
);
};
pass it to Table component
return (
<React.Fragment>
<TestTable
{...{
testButton}} />
</React.Fragment>
Then, table component will use it to render the table, with the buttons included.
export default function TestTable({
testButton,
...props
})
return (
{testButton});
Am I doing it correctly?
How can I export this from index.js, import in Table component.js, and render in Table component?
Thank you.
I think what you want is:
const TestTable = ({ children }) => {
return (
<table>
<tr>
<td>Something...</td>
<td>{children}</td>
</tr>
</table>
)
}
And then:
const App = () => {
return (
<TestTable>
<button>Test 1</button>
<button>Test 2</button>
<button>Test 3</button>
</TestTable>
)
}
Hope it helps!
The React library promotes component composition. For a good recent writeup of this pattern read Robin Wieruchs article
You can refactor your TestTable component like the following:
Here I have added a codesandbox example: https://codesandbox.io/embed/smoosh-cache-ytfky
import React from 'react'
export default function TestTable(props) {
return (
<React.Fragment>
{props.children}
</React.Fragment>
)
}
Your TestButton component can remain mostly the same. You need to add the export keyword to the beginning of the component. Actually, the components are just plain old functions.
To learn more about the different styles of exporting functions see Alex Rauschmayer great description. there are arguments for using either default exports or named exports, I personally prefer named exports which is more declarative and just easier for me to see what is happening.
export default function TestButton() {
return (
<React.Fragment>
<button>Test1</button>
<button>Test2</button>
<button>Test3</button>
<button>Test4</button>
<button>Test5</button>
</React.Fragment>
);
};
You can now compose your two components in another function as follows:
export function DisplayTable(props) {
return (
<TestTable>
<TestButton />
</TestTable>
)
}
NOTE:
This assumes all your functions are in one file, but it is better to
put them in their own file and import / export them.
The this keyword is only applicable if you are writing a class component, if you write a function component then all you get is props, but you have to explicitly declare it in your function arguments.
I have converted all your ES6 arrow functions into regular javascript functions, I find it is easier to conceptualise, and learn these are just regular functions, but in React land they are your components.
As for React Hooks, they are a new introduction to React since 16.8 which really solve a specific use case of being able to handle state and side effects without using classes. see the original docs for a great description
In your index.js (where you return the buttons):
const TestButtons = () => (
<>
<button>Test1</button>
<button>Test2</button>
<button>Test3</button>
<button>Test4</button>
<button>Test5</button>
</>
)
export default TestButtons
Then, in your table.js:
import TestButtons from 'path/to/index.js'
const TestTable = () => (
<TestButtons />
)
You should use the import statement to import a component from another file.

Passing props to children not working In React

This should be super simple for some of you. I have a super simple app that I am making to teach myself the glory that is React and reactDom. Currently, I am pulling from an API (which actually works!), however, I am unable to see any data when rendering to the screen. Literally just two components. I am sure that I am using props or state wrong here, I just don't know where. It's possible that my map function is the problem as well.
Here is the code:
Parent:
import React from "react";
import ReactDOM from "react-dom";
import axios from 'axios'
import { Table } from './Table'
export class DataList extends React.Component {
state = {
articles: []
}
componentDidMount() {
axios.get('http://127.0.0.1:8000/api/portblog/')
.then(res => {
this.setState({
articles: res.data
})
console.log(res.data)
})
}
render() {
return(
<div>
<Table id={this.state.articles.id} articles={this.state.articles} />
</div>
)
}
}
export default DataList
And the child:
import React from "react";
import PropTypes from "prop-types";
import key from "weak-key";
export const Table = (props) => (
<div>
<h1>Welcome to the Article List Page Home</h1>
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
</div>
);
export default Table;
The problem is that your map() call is not returning anything. You need to do something like:
<div>
<h1>Welcome to the Article List Page Home</h1>
{props.articles.map(article =>
<li>{article.titles}</li>
)}
</div>
I'm not exactly sure what your desired output is, but generally you map over data to generate a set of dom elements.
The problem is
<li>{props.articles.map((article) => {
{article.titles}
})}</li>
JSX expressions cannot be used in any arbitrary place. props.articles.map(...) is already an expression, so creating a new one wouldn't make sense.
{article.titles} inside a function creates a block that does nothing. Nothing is returned from map callback, the array isn't mapped to anything.
Depending on what should resulting layout look like, it should be either
<li>{props.articles.map((article) => article.titles)}</li>
output titles within single <li> tag, or
{props.articles.map((article) => <li>{article.titles}</li>)}
to output a list of <li> tags.
ESLint array-callback-return rule can be used to prevent the problem with callback return value.

React inline functions rerender issue

I have a component that uses two nested components that are based on render prop pattern. I need to combine props from both of them to be sent to the innermost function.
<Component1>
{(...props1) => (
<Component2>
{(...props2) => <MyComponent {...props1} {...props2} />}
</Component2>
)}
</Component1>
Now, I wanted to refactor the above inline functions into class functions, so as to avoid creating new functions on every render.
First attempt:
render() {
return <Component1>{this._render1}</Component1>;
}
_render1 = (...props1) => <Component2>{this._render2}</Component2>;
_render2 = (...props2) => <MyComponent {...props1} {...props2} />;
But now, in render2, I don't have access to props1, so I did:
render() {
return <Component1>{this._render1}</Component1>;
}
_render1 = (...props1) => <Component2>{this._render2(...props1)}</Component2>;
_render2 = (...props1) => (...props2) => <MyComponent {...props1} {...props2} />;
But here, I am back again to original problem of recreating inline functions on each render (inside _render2).
Please suggest a way to mitigate this problem. How can I best send the combined data down? What am I doing wrong here?
Did you got a chance to take a look on React.Context (https://reactjs.org/docs/context.html)?
You can create something like:
SomeContext.jsx
import React from "react";
export const SomeContext = React.createContext();
index.jsx
<SomeContext.Provider value={this.state.contextState}>
<div>
....
<Component2 />
<MyComponent />
...
</div>
</SomeContext.Provider>
Component2.jsx / MyComponent.jsx
import React from "react";
import { SomeContext } from "./SomeContext";
export default () => (
<SomeContext.Consumer>
your jsx with access to the props from parent.
</SomeContext.Consumer>
);
Hope it helps you.

Categories

Resources