React: change from class based components to functional based components - reactjs

This is a react beginners exercise so I'm looking for the simplest solution. I need to convert these 3 class components into functional components. I'm currently learning React so any helpful comments would also be appreciated. Thanks in advance!
APP.JS
import React from 'react'
import List from './components/List'
class DataArr extends React.Component {
render() {
const fruits = ["banana", "apple", "pear", "melon", "lemon"]
return (
<div className="DataArr">
<List fruits={fruits}/>
</div>
)
}
}
export default DataArr;
LIST.JS
import React from "react";
import Item from "./Item";
class List extends React.Component {
render() {
return (
<div>
{this.props.fruits.map((fruit, index) => {
return <Item key={index} fruit={fruit} />;
})}
</div>
);
}
}
export default List;
ITEM.JS
import React from 'react'
class Item extends React.Component{
render() {
return (
<div>
{this.props.fruit}
</div>
)
}
}
export default Item;

This is a step by step answer on How to Convert React Class Component to Functional Component which is nicer, cleaner and easier to read:
You need to change the class to a function
Remove render function
Remove this keyword
If you have state in your Class Component use hooks and in particular useState or useReducer hook
If you used lifecycle methods in your Class Component you can almost use useEffect hook in every situation. (just need to be comfortable with it which you can read more about it here and here)
App.js would be:
import React from 'react'
import List from './components/List'
// class DataArr extends React.Component { //<-- Remove this line
const DataArr = () => { // <-- Create a function Component
// render() { // <-- remove render function because you don't need it
const fruits = ["banana", "apple", "pear", "melon", "lemon"]
return (
<div className="DataArr">
<List fruits={fruits}/>
</div>
)
// } // this curly brace is for render function
}
export default DataArr;
List.js would be:
import React from "react";
import Item from "./Item";
// class List extends React.Component { //<-- Remove this line
const List = (props) => {
// render() { // <-- remove render function because you don't need it
return (
<div>
{
// this.props.fruits.map((fruit, index) => { <-- Change this.props to props
props.fruits.map((fruit, index) => {
return <Item key={index} fruit={fruit} />;
})}
</div>
);
// } // this curly brace is for render function
}
export default List;
and the ITEM.js would be like this:
import React from 'react'
// class Item extends React.Component{ //<-- Remove this line
const Item = (props) => { // <-- Create a function Component
// render() { // <-- remove render function because you don't need it
return (
<div>
{
// this.props.fruit // <-- change this.props to props
props.fruit
}
</div>
)
}
// } // this curly brace is for render function
export default Item;

In this particular instance, conversion is straight forward as they are simple 'dumb' components. You just remove the classes, convert them into standard functions with their props passed as a parameter, remove the render() and replace with a return.
APP.JS
import React from 'react'
import List from './components/List'
function DataArr() {
const fruits = ["banana", "apple", "pear", "melon", "lemon"];
return (
<div className="DataArr">
<List fruits={fruits}/>
</div>
);
}
export default DataArr;
LIST.JS
import React from "react";
import Item from "./Item";
function List({ fruits }) {
return (
<div>
{fruits.map((fruit, index) => {
return <Item key={index} fruit={fruit} />;
})}
</div>
);
}
export default List;
ITEM.JS
import React from 'react';
function Item({ fruit }) {
return (
<div>
{fruit}
</div>
);
}
export default Item;

APP.JS
import React from 'react';
import List from './components/List';
const DataArr = () => {
const fruits = ["banana", "apple", "pear", "melon", "lemon"];
return (
<div className="DataArr">
<List fruits={fruits} />
</div>
)
}
export default DataArr;
LIST.JS
import React from 'react';
import Item from './Item';
const List = (props) =>
{props.fruits.map(fruit, index) =>
<Item key={index} fruit={fruit} />};
export default List;
ITEM.JS
import React from 'react';
const Item = (props) => {props.fruit};
export default Item;

Related

react must be in scope when using jsx error

Very Simple code , I'hv checked react spelling, ReactDom imported, Please guide me about the error. I am new to the codding world.
import React, { Component } from "react";
import "./App.css";
import { Cardlist } from "./components/cardlist/cardlist.component.jsx";
class App extends Component {
constructor() {
super();
this.state = {
string: "Hello before",
};
}
render() {
return (
<div className="App">
<p>{this.state.string}</p>
<button onClick={() => this.setState({ string: "After text" })}>
Change text
</button>
<Cardlist name="this was prop" />
</div>
);
}
}
export default App;
Cardlist component
import react from "react";
export const Cardlist = (props) => {
console.log(props);
return <div>COngratulations</div>;
};
Try changing that react to React on first line on CardList ?

Error in Component re draw with memoized React component

This is my navbar component. Exports a memoized one.
import * as PropTypes from 'prop-types';
import Style from './Navbar.module.scss';
import NavbarItem from './NavbarItem';
import React from 'react';
/**
* #param items
* #param type
*/
export default function Navbar({ items }) {
return (
<nav className={Style.main}>
{items.map((item, i) => (
<NavbarItem name={item.name} url={item.url} items={item.items} key={item.name + i} />
))}
</nav>
);
}
export const MemoizedNavbar = React.memo(Navbar, true);
Navbar.propTypes = {
items: PropTypes.array.isRequired,
type: PropTypes.string,
};
Header that uses the Navbar.
import React, { Fragment, useContext } from 'react';
import Logo from './Logo';
import { MemoizedNavbar } from '../Navbar/Navbar';
import Style from './Header.module.scss';
import { ListContext } from '../../lib/Context/ListContext';
import BrandsHelper from '../../lib/List/BrandsHelper';
import { Items } from '../../config/SiteNavbar';
import Svg from '../Utils/svg';
const {useState} = require("react");
export default function Header({ brand }) {
const [lists, setLists] = useContext(ListContext);
const listData = lists.lists[lists.currentListId];
const [hamburgerMenuOpen, setHamburgerMenuOpen] = useState(false);
const handleHamburgerClick = () => {
setHamburgerMenuOpen(!hamburgerMenuOpen);
}
return (
<header className={Style.header}>
<section className={Style.section}>
<Logo brand={brandName} />
<MemoizedNavbar items={Items} />
<button className={Style.hamburgerButton} aria-label="Menu" onClick={handleHamburgerClick}>
<span className={Style.hamburgerButtonClickable} />
</button>
</section>
</header>
);
}
When I click in the HambugerButton, I get the following error:
If I don't use the Memoized component, it works just well.
What could be wrong?
export const MemoizedNavbar = React.memo(Navbar, true);
The second argument is expected to be a function, like:
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
If you don't need to do anything particular, just drop the second argument, and react will do a shallow comparison.
export const MemoizedNavbar = React.memo(Navbar);

React export React.createContext not defined

I am trying to learn React Context and got stuck. Need help.
App.js
import React from 'react';
import Header from './components/Header';
export const MyContext = React.createContext("Default");
class App extends React.Component {
render() {
return (
<MyContext.Provider value="dark">
<Header />
</MyContext.Provider>
);
}
}
export default App;
Header/index.js
import React, { Component } from 'react'
import { MyContext } from "./../../App";
class Header extends Component {
//static contextType = MyContext;
render() {
return (
<div>
{this.context}
</div>
)
}
}
Header.contextType = MyContext;
export default Header;
Got an error MyContext is not defined.
It works when i move Header class to App.js
What am i doing wrong? Tnx for your help
There are two ways to use context either use:
1. By using context consumer :
<MyContext.Consumer>
{
contextValue => {
return <div>
{value}
</div>
}
}
<MyContext.Consumer>
2. By assigning context to a object:
static contextType = MyContext;
render(){
const {value1,value2.......} = this.context
}
For more information about Context visit the React official page.
https://reactjs.org/docs/context.html
The provider only holds the the value for you(a bit like a store). It is the consumer that makes it available to your components.
Headerjs should look like this
// Header.js
import React, { Component } from 'react'
import { MyContext } from "./../../App";
class Header extends Component {
//static contextType = MyContext;
render() {
return (
<MyContext.Consumer>
{ value => {
return <div>
{value}
</div>
}}
<MyContext.Consumer>
)
}
}
// Header.contextType = MyContext; not needed for react v16+
export default Header;
To get more power out of Context i will suggest combining with Higher Order Components. for example if what you want is a theming system
you can do this.
import React from "react";
const themes = {
dark: {
background: "#333"
},
light: {
background: "#f5f5f9"
}
};
const { Provider, Consumer } = React.createContext(themes);
export const ThemeProvider = ({ children }) => {
return <Provider value={themes}>{children}</Provider>
};
export const withTheme = theme => {
return Component => props => <Consumer>
{themes => {
return <Component {...props} style={{ ...themes[theme]}} />;
}}
</Consumer>
};
in app.js
import Header from "./Header";
import { ThemeProvider } from './Theme'
class App extends React.Component {
render() {
return (
<ThemeProvider>
<Header />
</ThemeProvider>
);
}
}
and lastly Header.js
import React, { Component } from "react";
import { withTheme } from "./Theme";
class Header extends Component {
//static contextType = MyContext;
render() {
return <h1 style={{ ...this.props.style }}>Header</h1>;
}
}
export default withTheme("dark")(Header);
You can read MY article on using context for auth for more

how to compare state variables of 2 components in react?

I've a component, whose state has a variables that stores a random value of 0-3, I have 2 of this in my app.js, now I want to compare the state of the this 2 components. please help.
this is my component.
import React from "react";
export default class player extends React.Component {
constructor(...args) {
super(...args);
this.state = {
shoot: 0
};
}
shooter = () => {
this.setState({ shoot: Math.floor(Math.random() * Math.floor(3)) });
}
render() {
return (
<div>
<h1>{this.state.shoot}</h1>
<button onClick={() => this.shooter()}>shoot it</button>
</div>
);
}
}
this is my app.js
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import Player from "./player";
class App extends Component {
render() {
return (
<div className="App">
<div>
<Player />
<Player />
</div>
</div>
);
}
}
export default App;
How can I compare state.shoot in both <Player /> ? I want to check if both the state.shoot are equal.
I would recommend putting the state in the app component. this way you have more power on the data, for example :
App component:
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import Player from "./player";
class App extends Component {
constructor(...args) {
super(...aan rgs);
this.state = {
// create array of all your players
players : [{shoot :0}, {shoot :0}]
}
}
shooter = (id) => {
let players = this.state.player
/// maping the new players array
players.map(element, index => {
if(id == index){
element.shoot = Math.floor(Math.random() * Math.floor(3)
}
}
this.setState({players) });
}
checkPlayers = () =>{
// this is example... you can loop over your array and find what you need
if(this.state.players[0].shoot == this.state.players[1].shoot){
return true
}
else{
return false
}
}
render() {
return (
<div className="App">
<div>
{this.state.players.map(i => {
// pass the values to the player component (don't forget the id)
return <Player shoot={i.shoot} shooter={this.shooter} id={i}/>
}
</div>
</div>
);
}
}
export default App;
Player component:
import React from "react";
export default class player extends React.Component {
setShooter = () => {
this.props.shooter(this.props.id)
}
render() {
return (
<div>
<h1>{this.props.shoot}</h1>
<button onClick={this.setShooter}</button>
</div>
);
}
}
export default player;

Child(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null

I have two js files Child.js and App.js.
Child.js
import React from 'react';
const Child = (props) =>{
<div>
<button onClick={props.doWhatever}>{props.title}</button>
</div>
}
export default Child;
App.js
import React, { Component } from 'react';
import './App.css';
import Child from './components/parentTochild/Child.js'
class App extends Component {
state = {
title : 'Helloooo'
}
changeWorld = (newTitle) => {
this.setState = ({
title : newTitle
});
}
render() {
return (
<div className="App">
<Child doWhatever={this.changeWorld.bind(this , 'New world')} title={this.state.title}/>
</div>
);
}
}
export default App;
While executing this code I'm getting the error mentioned in the title. I have tried to solve it. But I couldn't figure out what's the problem with this code.
When I removed <Child doWhatever={this.changeWorld.bind(this , 'New world')} title={this.state.title}/> and typed a text it showed on screen. The problem is when using the Child component.
You should return some thing from child component.
import React from 'react';
const Child = (props) =>{
return (
<div>
<button onClick={(event)=>props.doWhatever('New world')}>{props.title}</button>
</div>
);
}
export default Child;
Updated:
If you want to send a text with the event handler to you can do this :
import React, { Component } from 'react';
import './App.css';
import Child from './components/parentTochild/Child.js'
class App extends Component {
constructor(props){
super(props);
this.state={
title : 'Helloooo'
};
this.changeWorld=this.changeWorld.bind(this);
}
changeWorld = (newTitle) => {
this.setState = ({
title : newTitle
});
}
render() {
return (
<div className="App">
<Child doWhatever={this.changeWorld} title={this.state.title}/>
</div>
);
}
}
export default App;

Resources