Pass a react value into a JS Alert - reactjs

Im attempting to learn a little bit of react and struggling with this simple concept. I know its just a syntax thing that I'm unfamiliar with but I just can't get it down.
Im attempting to create a tic tac toe game, where each square has a value. When the square is clicked, it should pop up an alert box that shows "You've clicked box {Box Number}". I cannot figure out how to pass the value to the alert function.
class Square extends React.Component {
render() {
return (
<button className="square" onClick={function() {alert("Youve clicked box " + this.props.value);}}>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
renderSquare(i) {
return <Square value={i} />;
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
<div>{/* status */}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);

Looking at your code and based on your comment, the issue is that you're trying to access the props attribute of an object (this) that doesn't have the props attribute.
One way you can do this is to use an arrow function.
<button onClick={() => { alert(`Something ${this.props.value}`); }>Click Me</button>
Another way is to bind the function.
class Box extends React.Component {
constructor(props) {
super(props)
this.onClick = this.onClick.bind(this)
}
onClick() {
alert()
}
render() {
return (
<button onClick={this.onClick}>Click Me</button>
)
}
}
Alternatively, you can directly use an arrow function inside your class so you don't have to bind if you don't want to define one in the render function.
class Box extends React.Component {
onClick = () => {
alert()
}
render() {
return (
<button onClick={this.onClick}>Click Me</button>
)
}
}
Demo: https://jsfiddle.net/1wfyq68r/

You're re-binding the context of this by using a function declaration in your onClick. When you refer to this inside of that function, you're now referring to the context of that function, not the Square class (where this.props would reside).
Any easy fix is to use an arrow function instead–it does not rebind the context of this.
<button
className="square"
onClick={() => alert("Youve clicked box " + this.props.value)}
>
{this.props.value}
</button>

You need to set the context of the click handler function so it references the correct this. This can be done by either
Using an arrow function
() => alert("Youve clicked box " + this.props.value)
Explicitly binding
function() {
alert("Youve clicked box " + this.props.value);
}.bind(this)
A useful resource as to why this is required here

Related

Handle multiple child component in React

I've tried to look everywhere and couldn't find anything related to my use case, probably I'm looking for the wrong terms.
I have a situation where I have a bar with 3 icons, I'm looking for set one icon "active" by changing the class of it.
The icon is a custom component which have the following code
export default class Icon extends Component {
state = {
selected : false,
}
setSelected = () => {
this.setState({
selected : true
})
}
setUnselected = () => {
this.setState({
selected : false
})
}
render() {
var classStatus = '';
if(this.state.selected)
classStatus = "selected-icon"
else
classStatus = "icon"
return <div className={classStatus} onClick={this.props.onClick}><FontAwesomeIcon icon={this.props.icon} /></div>
}
}
In my parent component I have the following code
export default class MainPage extends Component {
handleClick(element) {
console.log(element);
alert("Hello!");
}
render() {
return (
<div className="wrapper">
<div className="page-header">
<span className="menu-voice">File</span>
<span className="menu-voice">Modifica</span>
<span className="menu-voice">Selezione</span>
</div>
<div className="page-main">
<span className="icon-section">
<div className="top-icon">
<Icon icon={faFileCode} onClick={() => this.handleClick(this)} />
<Icon icon={faCodeBranch} onClick={() => this.handleClick(this)} />
<Icon icon={faMagnifyingGlass} onClick={() => this.handleClick(this)} />
</div>
</span>
<span className="files-section">Files</span>
<span className="editor-section"></span>
</div>
<div className="page-footer">
Footer
</div>
</div>
);
}
}
What I'm trying to achieve is that when one of the Icon child component get clicked it will set the selected state to true manage by the parent component, in the same time while one of them is true I would like that the parent would set to false the other twos.
I've tried to use the useRef function but it doesn't look as a best practise.
Which is the correct way to do it? Sending also this to the handleClick function it just return the MainPage class instead of the child. Any suggestion at least where I should watch?
Thanks in advance
I suggest not storing the state in the icon, since it doesn't know what else you're using it for. Simply have the icon component take it's 'selected' status from props. e.g.
export default class Icon extends Component {
render() {
var classStatus = '';
if(this.props.selected)
classStatus = "selected-icon"
else
classStatus = "icon"
return (
<div className={classStatus} onClick={this.props.onClick}>.
<FontAwesomeIcon icon={this.props.icon} />
</div>
);
}
};
Then you can just manage the state in the parent where it should be:
export default class MainPage extends Component {
constructor(props) {
super(props);
this.state = { selectedOption : '' };
}
handleSelectOption(newValue) {
this.setState({ selectedOption: newValue });
}
isSelected(value) {
return value === this.state.selectedOption;
}
render() {
return (
<div className="wrapper">
{ /* etc... */ }
<div className="page-main">
<span className="icon-section">
<div className="top-icon">
<Icon
icon={faFileCode}
onClick={() => this.handleSelectOption("File")}
selected={isSelected("File")}
/>
<Icon
icon={faCodeBranch}
onClick={() => this.handleSelectOption("Modifica")}
selected={isSelected("Modifica")}
/>
{ /* etc... */ }
</div>
</span>
</div>
{ /* etc... */ }
</div>
);
}
};
You should define a constructor in your class component:
constructor(props) {
super(props);
this.state = { selected : false };
}
You also have to call a function which modify the state when you click on the Icon. onClick={this.props.onClick} doesn't change the state

i`m a React beginner and function setState() is not working, and i need your help guys

I'm currently studying React and tried to make To-do list. Below is the source code.
I want to change the state "display" of the Frame component by clicking the button. I found out that the handler I addEventListener'd to the button element worked, but the state display never changed and even there are no errors on console. Why?
Frame Component
class Frame extends Component {
state = {
list: ["왜", "안돼냐"],
display: "before!!!",
};
registerHandler = () => {
this.setState = {
display: "after",
};
};
render() {
return (
<div className="frame">
<h1>To-Do-Lists</h1>
<h2>{this.state.display}</h2>
<div className="wrapper">
<Lists list={this.state.list} />
</div>
<div className="action">
<Button name="Register" onClick={this.registerHandler} />
</div>
</div>
);
}
}
export default Frame;
Button 관련 부분
import React, { Fragment } from "react";
const button = (props) => {
return (
<Fragment>
<button onClick={props.onClick} className="action button">
{props.name}
</button>
</Fragment>
);
};
export default button;
Mby you trying to set this.setState equal to something, try use it like this this.setState({})

Reactjs - how to append a font-awesome icon to ref

I'm trying to use appendChild to add a fontawesome icon to a ref in react. I get the error:
Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
Using append instead of appendChild can only add text.
class Example extends React.Component {
handle = (e) => {
e.target.appendChild('<i className="fas fa-minus-circle"/>')
}
render() {
return (
<div className="container">
<button onClick={this.handle}>CLICK HERE</button>
</div>
)
}
}
Consider changing your approach a little. You can achieve the same result you're expecting with the code below, and it's a little more common to use state and conditional JSX in React:
class Example extends React.Component {
state = { images: [] }
handle = () => {
this.setState({ images: [...images, 'fas fa-minus-circle'] });
}
render() {
return (
<div className="container">
<button onClick={this.handle}>CLICK HERE</button>
{this.state.images.map((image, index) => {
<i key={index} className={image} />
})}
</div>
);
}
}
You can create ref and attach it to the element you want to add the icon.
class Example extends React.Component{
constructor(props){
super(props);
this.iconRef= React.createRef();
}
handle = (e) => {
e.prenventDefault();
this.iconRef.current.appendChild('<i className="fas fa-minus-circle"/>')
}
render() {
return (
<div className="container">
<button ref={this.iconRef} onClick={this.handle}>CLICK HERE</button>
</div>
)
}
}

Modal isn't opening as expected

class Posts extends Component {
constructor(){
super();
this.state = {
modalIsOpen:false
};
this.openModal = this.openModal.bind(this);
this.afterOpenModal = this.afterOpenModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
openModal() {
console.log("got here?")
this.setState({modalIsOpen: true});
}
afterOpenModal() {
// references are now sync'd and can be accessed.
this.subtitle.style.color = '#f00';
}
closeModal() {
this.setState({modalIsOpen: false});
}
render() {
const keys = generateKey(new Date().getTime())
var dictionary = this.props.posts
const postItemsArr = Object.keys(dictionary).map(post=>dictionary[post])
const number = 0
const postItems = postItemsArr.map(
post=>(
<Jumbotron key={generateKey(post.positiontitle) + generateKey(post.businessId)} >
<div className="position">{post.positiontitle}</div><br></br>
<BusinessName businessnameType={post.businessname} /><br></br>
<JobDescription jobDescription={post.description_sanitized} /><br></br>
<p>
<Modal isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Example"
>
<h2 ref={subtitle => this.subtitle = subtitle}>Hello</h2>
<button onClick={this.closeModal}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
<button onClick={this.openModal}>Open Modal</button>
</p>
</Jumbotron>
)
)
return (
<div>
<h1> Jobs Listings </h1>
{postItems }
</div>
);
}
}
Inside my Jumbotron, my modal doesn't seem to be opening, why?
It looks like it gets to the state openModal()
but doesn't actually open the modal when the user clicks on
<button onClick={this.openModal}>Open Modal</button>
Also; should I create a separate component called Modal; what would be best practices?
Overall I'm trying to trigger the modal object for a respective list item in the list.
I would create a new presentational component called modal, then use that when you need it, rather than do what you're trying to do now, which is pass an open/close state. The Modal can be a simple presentational component that just accepts props. By doing it this way, you create reusability.
function Modal(props) {
return (
<div className={props.css.awesomeLayout}>
{props.aProp}
</div>
)
}

Accessing props to mapped objects in render method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I'm trying to create a dynamic list of views managed in a home component that can be saved and loaded. The save and load functions work fine but I get the following error when calling it in the span's returned from the map function in the Footer.js render method
Uncaught TypeError: Cannot read property 'props' of undefined
How can I access this function call in these elements?
Footer.js
export default class Footer extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="footer hbox">
<div className="views hbox">
<span onClick={ (e) => this.props.getViewNames() }>Get Views</span>
<span onClick={ (e) => this.props.saveView('test3')}>Save View</span>
<span onClick={(e) => this.props.loadView('test3')}>Load View</span>
{this.props.getViewNames().map(function(viewName){
return (
<span onClick={(e)=>this.props.loadView(viewName)}>
{viewName}
</span>
);
})}
</div>
);
}
}
You forgot to use an arrow function for getViewNames.map(), and thus the lexical scope of this is not kept in your code -- which is interesting, considering you did use the correct approach everywhere else.
So just do:
this.props.getViewNames().map(viewName => {
...
});
Also see:
How to access the correct `this` context inside a callback?
The reason you cannot access props inside the map function is because this inside your function refers to the context of the map function, and not React Component. You will need to bind your map function to the React Component context by using bind(this) on the map function or arrow functions
Using bind(this)
export default class Footer extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="footer hbox">
<div className="views hbox">
<span onClick={ (e) => this.props.getViewNames() }>Get Views</span>
<span onClick={ (e) => this.props.saveView('test3')}>Save View</span>
<span onClick={(e) => this.props.loadView('test3')}>Load View</span>
{this.props.getViewNames().map(function(viewName){
return (
<span onClick={(e)=>this.props.loadView(viewName)}>
{viewName}
</span>
);
}.bind(this))}
</div>
);
}
}
using arrow function
export default class Footer extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="footer hbox">
<div className="views hbox">
<span onClick={ (e) => this.props.getViewNames() }>Get Views</span>
<span onClick={ (e) => this.props.saveView('test3')}>Save View</span>
<span onClick={(e) => this.props.loadView('test3')}>Load View</span>
{this.props.getViewNames().map((viewName) => {
return (
<span onClick={(e)=>this.props.loadView(viewName)}>
{viewName}
</span>
);
})}
</div>
);
}
}

Resources