Understanding the ReactJS quiz from Solo Learn - reactjs

Hello so I am trying to practice React form solo learn so I have a quiz that they gave that I do not understand however through guessing I got the answer(i.e "OFF") however I would love to now understand why this answer is the correct answer.
Question:
What will be the value on the button after it is clicked 5 times?
Code below:
function Toggle() {
const [val, setVal] = useState("ON");
function toggle() {
setVal((val == "ON")? "OF":"ON");
}
return <button onClick={toggle}> {val} </button>;
}

As you may know, this is a functional component which displays a button. On clicking the button, the function toggle() is called. This function changes the value of the button from ON to OFF, and vice versa.
The button starts with "ON" and changes to "OFF every time you click on it.
Therefore, after clicking on it 5 times, the result is "OFF".

Look this example which show previous state of the val state. After you click five times the button will be disabled.
I'm not using functional component as stackoverflow doesn't support it.
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {
val: "ON",
history: []
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
val : (this.state.val == "ON")? "OF":"ON",
history: [...this.state.history, this.state.val]
});
this.s
}
render() {
return <div>
<h3>previous state</h3>
<ul>
{this.state.history.map((h, i) => {
return <li key={i}>{i + 1} val = {h}</li>
})}
</ul>
<button onClick={this.toggle}
disabled={this.state.history.length === 5}>
{this.state.val}
</button>
</div>;
}
}
ReactDOM.render(<Toggle />, document.getElementById('root'));
<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="root"></div>

Related

Focus an input after clicking on a button

I am currently trying to learn React by making a Todo list (original I know). There a lot of concepts I haven't learnt yet (I'm still using class components) but I was wondering is there a recommended way to focus the input that appears when the edit button is pushed?
I tried using createRef but it still seems not to work. I'm wondering I the input should be a separate component that focuses onMount?
Any direction would be appreciated:
export class Item extends Component {
constructor(props){
super(props)
this.editInput = React.createRef()
this.state = {
editView: false
}
this.handleRemove = this.handleRemove.bind(this);
this.toggleView = this.toggleView.bind(this);
this.editMode = this.editMode.bind(this);
}
handleRemove(e){
this.props.remove(this.props.detail);
}
toggleView(){
this.setState(prevState => (
{editView: !prevState.editView }
))
}
editMode(){
this.toggleView();
this.editInput.current.focus();
}
render() {
const itemView = !this.state.editView ?<div className="item">{this.props.detail}</div> : <input ref={this.editInput} className="edit-item-input" placeholder={this.props.detail + "..."}></input> ;
return (
<div className="item-container">
{itemView}
<div className="buttons">
<button onClick={this.editMode} className="button button-edit">Edit</button>
<button onClick={this.handleRemove} className="button button-delete">Delete</button>
</div>
</div>
)
}
}
You could add the React autoFocus property, on the input element, and it should work as you want.

To change color on onclick event using react

I need to change the colour of a div tag which I have designed when it is clicked. I need to change the colour of the div and I need to add a class to the div when it is clicked, which I need answer in react
Like others mentioned, a little more code details would be nice from your side.
One of the ways to achieve what you want: https://jsfiddle.net/hawk939393/Ly0912nf/
class TodoApp extends React.Component {
state = {
divClicked: false
};
getClassname = () => {
return !this.state.divClicked ?
"toDoApp" : "toDoApp-isClicked"
};
render() {
return (
<div
className={this.getClassname()}
onClick={() => this.setState(prevState => ({divClicked: !prevState.divClicked}))}>
Hello world!
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
^ Have a state that tracks whether a div's className has been changed.

Setting focus via a ref only works in setTimeout in React?

My code below works but the this.buttonRef.current.firstChild.focus() stops working if it's not in a setTimeout function.
From looking at the official docs for refs I cant see why this is happening. Is there anything obviously wrong with my component? If not Im wondering if another component on my site is 'stealing' focus as when the url prop changes a modal is closed.
UPDATE: One weird thing is if I console.log outside of the setTimeout then I can see the element is present in the DOM.
UPDATE2: Turns out it was React Trap Focus in my modal that was causing the issue. Removing the focus trap means I don't need the timeout. As I need the focus trap I think the setTimeout will need to stay.
https://github.com/davidtheclark/focus-trap-react
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.buttonRef = React.createRef();
}
componentDidUpdate(prevProps) {
if (this.props.url === '' && prevProps.url = "old-url") {
console.log('target element: ', this.buttonRef.current.firstChild)
// This doenst work if not in a setTimeout
// this.buttonRef.current.firstChild.focus();
setTimeout(() => {
this.buttonRef.current.firstChild.focus();
}, 1);
}
}
render() {
const {
limitIsReached,
add
} = this.props;
return (
<Fragment>
<Title>My title</Title>
<Section>
<Button>
Add a promo code
</Button>
<span ref={this.buttonRef}>
{limitIsReached ? (
<Alert
message="Sorry limit reached"
/>
) : (
<Button
onClick={add}
>
Add new
</Button>
)}
</span>
<List compact />
</Section>
</Fragment>
);
}
}
export default MyComponent;
Considering that seemingly componentDidUpdate runs before your buttonRef is resolved, a short setTimeout isn't the worst solution.
You could try other ways involving setting state:
componentDidUpdate(prevProps) {
if (.... oldurl) {
this.setState({focusBtn: true})
}
Then when the buttonref resolves:
<span ref={ref=>{
if (this.state.focusBtn) {
this.buttonRef = ref;
this.buttonRef.current.firstChild.focus();
} } >...
EDIT
ok so if you remove the conditional in your render method, React will ensure that your ref has resolved on componentDidMount and also componentDidUpdate (as you wish it to be)
Try this:
<span ref={this.buttonRef}>
<Alert
message="Sorry limit reached"
style={{display: limitIsReached ? 'block' : 'none'}}
/>
<Button
onClick={add} style={{display: limitIsReached ? 'none' : 'inline-block'}}
>
Add new
</Button>
)}
</span>

Can't get button component value onClick

I'm sure this is something trivial but I can't seem to figure out how to access the value of my button when the user clicks the button. When the page loads my list of buttons renders correctly with the unique values. When I click one of the buttons the function fires, however, the value returns undefined. Can someone show me what I'm doing wrong here?
Path: TestPage.jsx
import MyList from '../../components/MyList';
export default class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
console.log("button click", event.target.value);
}
render() {
return (
<div>
{this.props.lists.map((list) => (
<div key={list._id}>
<MyList
listCollection={list}
handleButtonClick={this.handleButtonClick}
/>
</div>
))}
</div>
);
}
}
Path: MyListComponent
const MyList = (props) => (
<div>
<Button onClick={props.handleButtonClick} value={props.listCollection._id}>{props.listCollection.title}</Button>
</div>
);
event.target.value is for getting values of HTML elements (like the content of an input box), not getting a React component's props. If would be easier if you just passed that value straight in:
handleButtonClick(value) {
console.log(value);
}
<Button onClick={() => props.handleButtonClick(props.listCollection._id)}>
{props.listCollection.title}
</Button>
It seems that you are not using the default button but instead some sort of customized component from another libray named Button.. if its a customezied component it wont work the same as the internatls might contain a button to render but when you are referencing the event you are doing it throug the Button component

react-dom: Incrementally change opacity of an element on click

I'd like to be able to increase opacity of a DOM element on click of a button.
Wrapping my head around React's concepts, I think this should be done through using state and a functional setState() function.
However, I keep running into an error with the following code:
import React, { Component } from 'react'
class ThoughtfulThoughts extends Component {
state = {
opacity: 0.4,
thoughts:
[
"live and let leave",
"just pee yourself",
"who knows what 'laf' is?"
]
}
makeAppear = () => {
// TODO: this causes a "RangeError: Maximum call stack size exceeded"
this.setState(prevState => ({
opacity: prevState.opacity + 0.2
}))
}
render() {
return (
<div className="thoughtful-thoughts">
<div className="current-thought" style={{opacity: this.state.opacity}}>
{this.state.thoughts.map((thought, i) => (<p>{thought}</p>))}
</div>
<button onClick={this.makeAppear()}>Think for me</button>
</div>
)
}
}
export default ThoughtfulThoughts
I don't want to use jQuery, nor direct DOM manipulation, nor
CSS transitions, but would like to do this just in JS in "the React way".
Any pointers would be greatly appreciated!
You have a couple of minor issues in your code:
On your button component, change onClick={this.makeAppear()} into onClick={this.makeAppear}.
Nicely done on using the function approach instead of the object approach for updating a state variable based on a previous state variable. However, you have a minor syntax. Either do:
this.setState(prevState => (
{opacity: prevState.opacity + 0.2}
));
or
this.setState(prevState => {
return {opacity: prevState.opacity + 0.2}
});
whichever you prefer.
Add a key property to each item you return from your map(): So basically:
{this.state.thoughts.map((thought, i) => (<p key={i}>{thought}</p>))}
You can probably use i safely as the key here because the order of the items in thoughts array will remain static. For more info about keys and how to use them properly, take a look here.
Demo:
class ThoughtfulThoughts extends React.Component {
constructor() {
super();
this.state = {
opacity: 0.4,
thoughts:
[
"live and let leave",
"just pee yourself",
"who knows what 'laf' is?"
]
}
}
makeAppear = () => {
this.setState(
prevState => ({opacity: prevState.opacity + 0.2})
);
}
render() {
return (
<div className="thoughtful-thoughts">
<div className="current-thought" style={{opacity: this.state.opacity}}>
{this.state.thoughts.map((thought, i) => <p key={i}>{thought}</p>)}
</div>
<button onClick={this.makeAppear}>Think for me</button>
</div>
);
}
}
ReactDOM.render(<ThoughtfulThoughts />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Resources