how to compare state variables of 2 components in react? - reactjs

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;

Related

Hide a component and display another component within a component page - react js

I have a application in which I have created three components.js page as below.
one.component.js:
import React, { Component } from "react";
import TwoComponent from 'two.component';
import ThreeComponent from 'three.component';
export default class OneComponent extends Component {
render() {
return (
<>
Hi!
<TwoComponent />
<ThreeComponent />
<>
)
}
}
two.component.js:
import React, { Component } from "react";
export default class TwoComponent extends Component {
render() {
return (
<>
Hi Two Component!
</>
)
}
}
three.component.js:
import React, { Component } from "react";
export default class ThreeComponent extends Component {
render() {
return (
<>
Hi Three Component!
</>
)
}
}
Now, I want only the component has to be displayed and the other has to be hided.
With in two.component.js I have a button. On clicking the button, I need to show three.component.js and the two.component.js has to be hided.
Modified the above files as below.
one.component.js:
import React, { Component } from "react";
import TwoComponent from 'two.component';
import ThreeComponent from 'three.component';
export default class OneComponent extends Component {
render() {
return (
<>
Hi!
{
this.state.count === 2 ?
<TwoComponent twoButtonClicked={this.props.triggerButtonClick} />
:
<ThreeComponent />
}
<>
)
}
triggerButtonClick(){
this.setState({ count: 2 });
}
}
two.component.js:
import React, { Component } from "react";
export default class TwoComponent extends Component {
render() {
return (
<>
<input type="button" onClick={this.twoButtonClicked} />
</>
)
}
}
Here, the function triggerButtonClick is not triggering.
Kindly help me to display the components based on condition from within one of the component. Thanks in advance.
In component two.component.js, you are accessing twoButtonClicked method passed as prop like this.twoButtonClicked but you should be accessing it like this.props.twoButtonClicked.
import React, { Component } from "react";
export default class TwoComponent extends Component {
render() {
return (
<>
<input type="button" onClick={this.props.twoButtonClicked} />
</>
)
}
}
I have updated your code and added a snippet below, please check
const { Component, Fragment } = React;
class TwoComponent extends Component {
render() {
return (
<Fragment>
<input type="button" onClick={this.props.twoButtonClicked} />
</Fragment>
);
}
}
class ThreeComponent extends Component {
render() {
return <Fragment>Hi Three Component!</Fragment>;
}
}
class OneComponent extends Component {
constructor(props) {
super(props);
this.state = {
//initialised count as `2` so as to display component two by default
count: 2
};
}
//Converted to an arrow function in order to use this method
//like `this.triggerButtonClick` otherwise we should bind this
//method in the constructor
triggerButtonClick = () => {
//Updating the count to `3` so as to hide component two.
this.setState({ count: 3 });
};
render() {
return (
<Fragment>
Hi!
{this.state.count === 2 ? (
<TwoComponent twoButtonClicked={this.triggerButtonClick} />
) : (
<ThreeComponent />
)}
</Fragment>
);
}
}
ReactDOM.render(<OneComponent />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
First, fix Syntax Errors in your code.
Then follow best practices when your coding. For example, we always add the render method at the end of the component.
Fixes that made to your code, to work as expected mentioned below.
one.component.js:
import React, { Component } from "react";
import TwoComponent from './two.component';
import ThreeComponent from './three.component'; // Fix 7 - Update component import statements with './'
export default class OneComponent extends Component {
state = {
count: 2, // Fix 2 - According to your requirement this should be 2.
}; // Fix 1 - Define the state property
triggerButtonClick = () => {
this.setState({ count: 1 }); // Fix 4 - When consider your requirement this should be other than 2.
} // Fix 3 - Use an arrow function here to define the method.
render() {
return (
<>
Hi!
{
this.state.count === 2 ?
<TwoComponent twoButtonClicked={this.triggerButtonClick} />
:
<ThreeComponent />
}
{/* Fix 5 - Remove this.props.triggerButtonClick and add this.triggerButtonClick */}
<>
)
}
}
two.component.js:
import React, { Component } from "react";
export default class TwoComponent extends Component {
render() {
return (
<>
<input type="button" onClick={this.props.twoButtonClicked} />
{/* Fix 6 - Get twoButtonClicked from the props object. */}
</>
)
}
}

React: change from class based components to functional based components

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;

React Context and Next JS

I'm trying to add simple React Context to my app. I create Context in "./components/DataProvider.js" that looks like this:
import React, { Component } from 'react'
const DataContext = React.createContext()
class DataProvider extends Component {
state = {
isAddButtonClicked: false
}
changeAddButtonState = () => {
if( this.state.isAddButtonClicked ) {
this.setState({
isAddButtonClicked: false
})
} else {
this.setState({
isAddButtonClicked: true
})
}
}
render() {
return(
<DataContext.Provider
value={{
isAddButtonClicked: this.state.isAddButtonClicked,
changeAddButtonState: () => {
if( this.state.isAddButtonClicked ) {
this.setState({
isAddButtonClicked: false
})
} else {
this.setState({
isAddButtonClicked: true
})
}
}
}}
>
{this.props.children}
</DataContext.Provider>
)
}
}
const DataConsumer = DataContext.Consumer
export default DataProvider
export { DataConsumer }
Which then I added to "./pages/_app.js"
import App, { Container } from 'next/app'
import DataProvider from '../components/DataProvider'
class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Container>
<DataProvider>
<Component {...pageProps} />
</DataProvider>
</Container>
)
}
}
export default MyApp
And consume it in "./components/AddPostButton.js".
import React, {Component} from 'react'
import { DataConsumer } from './DataProvider'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faPlus } from '#fortawesome/free-solid-svg-icons'
class AddPostButton extends Component {
render() {
return (
<div>
<DataConsumer>
{({ changeAddButtonState }) => (
<a onClick={changeAddButtonState}>
<FontAwesomeIcon icon={faPlus} color='#fff' />
</a>
)}
</DataConsumer>
</div>
)
}
}
export default AddPostButton
But I get this error "Cannot read property 'changeAddButtonState' of undefined". I'm using React 16.7 and NextJS 7.0.2. Don't know what is wrong.
The second question is should I use one Context for everything or just use them as Model in MVC pattern?
I fixed it by moving changeAddButtonState to Context Component state so my DataProvider.js now looks like this
import React, { Component } from 'react'
const DataContext = React.createContext()
class DataProvider extends Component {
state = {
isAddButtonClicked: false,
changeAddButtonState: () => {
if (this.state.isAddButtonClicked) {
this.setState({
isAddButtonClicked: false
})
} else {
this.setState({
isAddButtonClicked: true
})
}
}
}
render() {
return(
<DataContext.Provider
value={this.state}
>
{this.props.children}
</DataContext.Provider>
)
}
}
const DataConsumer = DataContext.Consumer
export default DataProvider
export { DataConsumer }
And then in AddButton component I changed code to look like this
import React, {Component} from 'react'
import { DataConsumer } from './DataProvider'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faPlus } from '#fortawesome/free-solid-svg-icons'
class AddPostButton extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<DataConsumer>
{(context) => (
<a onClick={context.changeAddButtonState}>
<FontAwesomeIcon icon={faPlus} color='#fff' />
</a>
)}
</DataConsumer>
</div>
)
}
}
export default AddPostButton

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;

sending function throw `spread operator` not works but state value added

I am passing a function and a state value throw spread operator. the state value update in the html. but while click on button function not calling at all.
What is the correct way to send the function to children using spread operators in reactjs?
Here is my code :
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Counter extends React.Component {
render() {
return (
<div>
<div>{this.props.display}</div>
<button onClick={this.props.fun}>+</button> //onclick not works!!
</div>
);
}
}
class CounterParent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0 //added
};
}
increase = () => { //not called
this.setState({
count: this.state.count + 1
});
};
render() {
let object = {
display: this.state.count,
func: this.increase
};
return (
<div >
<Counter {...object} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<CounterParent />, rootElement);
In Counter component, you mispelled func name.
class Counter extends React.Component {
render() {
return (
<div>
<div>{this.props.display}</div>
<button onClick={this.props.func}>+</button>
</div>
);
}
}

Resources