React state not updating - reactjs

So I'm making a simple React application that needs to show a modal when something is clicked. I use react-modal to achieve this and the modal is showing but I'm not able to close it again. Here's the code:
import React from 'react';
import ReactDOM from 'react-dom';
import Paper from "./Paper";
ReactDOM.render(
<Paper title={"Title"} notes={"Notes"}/>,
document.getElementById('root')
);
and the Paper definition:
import React, {Component} from 'react';
import Modal from 'react-modal';
class Paper extends Component {
constructor(props) {
super(props);
this.state = {modalIsOpen: false};
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
showModal() {
this.setState({modalIsOpen: true});
}
closeModal() {
this.setState({modalIsOpen: false});
}
render() {
return (
<div onClick={this.showModal}>
{this.props.title}
<Modal isOpen={this.state.modalIsOpen}>
<button onClick={this.closeModal}>close</button>
{this.props.notes}
</Modal>
</div>
);
}
}
The state just doesn't get updated if I check it in the developer tools and I have no idea why. Anyone who can help me?

I was able to reproduce your problem, which was actually a bit strange - even if I logged this.state.modalIsOpen in the setState callback after it was set to false, the value was still true. At any rate, I changed the code to perform a toggle instead and it resolved the issue:
https://codesandbox.io/s/q38nzl9yy9
toggleModal() {
this.setState({ modalIsOpen: !this.state.modalIsOpen });
}
render() {
return (
<div onClick={this.showModal}>
{this.props.title}
<Modal isOpen={this.state.modalIsOpen}>
<button onClick={this.closeModal}>close</button>
{this.props.notes}
</Modal>
</div>
);
}
I'm still digging into why the this context seems to be getting muddled, since this appears to be a straightforward example.

Related

Why I can't use an imported component inside a functional component in React?

I am new to React. For the code readability, instead of in-line styled button, I want to write it as a separate class component. I created a customed button 'addImageButton'and imported it to another .js file. It doesn't render the customer button when I try to use it within a functional component. How can I make the functional component be able to use the imported button? Thanks!
//addImageButton.js
import React, { Component } from "react";
class addImageButton extends Component {
render() {
return (
<div>
<button
style={{
borderStyle: "dotted",
borderRadius: 1,
}}
>
<span>Add Image</span>
<span>Optional</span>
</button>
</div>
);
}
}
export default addImageButton;
//AddNewTaskButton.js
import React, { Component } from "react";
import Modal from "react-modal";
**import addImageButton from "../addImageButton";**
class AddNewTaskButton extends Component {
constructor(props) {
super(props);
this.state = {
show: false,
};
this.setShow = this.setShow.bind(this);
this.closeShow = this.closeShow.bind(this);
this.addTaskModal = this.addTaskModal.bind(this);
}
setShow() {
this.setState({
show: true,
});
}
closeShow() {
this.setState({
show: false,
});
}
addTaskModal = () => {
return (
<div>
<Modal
isOpen={this.state.show}
onRequestClose={() => this.closeShow()}
>
**<addImageButton />**
</Modal>
</div>
);
};
render() {
return (
<div>
<button onClick={() => this.setShow()}>
<img src={addIcon} alt={text}></img>;
<span>text</span>
</button>
<this.addTaskModal className="modal" />
</div>
);
}
}
export default AddNewTaskButton;
Easier way would be to just use functional components. Also, react components should be upper case, like so:
export default function AddImageButton() {
return (
<div>...</div>
)
}
create a different component for Modal
import Modal from './Modal'
import AddImageButton from './AddImageButton'
function AddTaskModal() {
return (
<div>
<Modal> <AddImageButton/> </Modal>
</div>
)
}
then
import AddTaskModal from './AddTaskModal'
function AddNewTaskButton() {
return (
<div>
<AddTaskModal/>
</div>
)
}
I don't know your file directories, so I just put randomly.
as for your question, try to make the AddImageButton as a class and see if it renders then. If it doesn't it might be due to something else. Do you get errors? Also maybe create the AddTaskModal class separately and render it out as a component. Maybe that'll help

How to check whether React updates dom or not?

I wanted to check how to react does reconciliation so I updated the inner HTML of id with the same text. Ideally, it shouldn't update the dom but it is paint reflashing in chrome.
I have tried paint reflashing in chrome it is showing green rectangle over that same text
import React from 'react';
function App() {
return (
<div >
<p id="abc" key="help">abc is here</p>
<button onClick={function () {
// document.getElementById("may").innerHTML = "";
document.getElementById("abc").innerHTML = "abc is here";
}} > Btn</button>
</div>
);
}
export default App;
Expected result should be that paint reflashing shouldn't happen but it is happening.
You are not using React here to update the text of your p tag but directly updating the DOM with JavaScript.
So React reconciliation algorithm doesn't even run here.
In React, the output HTML is a result of the state and the props of your component.
When a change in state or props is detected, React runs the render method to check if it needs to update the DOM. So, in order to do this check, you need to store the parameters that determine your view in state or props.
Given your example, we could save the text you want to show in the p tag in the state of your component (using hooks):
import React, { useState } from 'react';
function App () {
const [text, setText] = useState('abc is here');
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => setText('abc is here') }>Btn</button>
</div>
);
}
}
export default App;
If you are using a version of React that does not support hooks, you will need to transform your functional component into a class to use state:
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = { text: 'abc is here' };
}
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => this.setState({ text: 'abc is here' }) }>Btn</button>
</div>
);
}
}
export default App;

reactjs-popup didn't open as ever after closeOnDocumentClick event triggered

The demo case is here. To regenerate it, just do as follows:
click on [Click me.], then the popup will show;
click anywhere but the popuped block, the popup will hide;
click on [Click me.], it's expected that the popup window will show again, but the fact is just the opposite.
What's the problem? Any ideas?
Use onClose prop of reactjs-popup as shown below.
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import Popup from "reactjs-popup";
class App extends Component {
constructor() {
super(
);
this.onClick = this.onClick.bind(this);
this._popUpClosed = this._popUpClosed.bind(this);
this.state = {
name: 'React',
open:false
};
}
_popUpClosed(){
this.setState({open: false});
}
onClick() {
this.setState({open: true});
}
render() {
return (
<div>
<Popup open={this.state.open} onClose={this._popUpClosed}/>
<Hello name={this.state.name} />
<button onClick={this.onClick}>
Click me.
</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
it seems like you need to make open false again so that the popup can show up when you change the state of open
you can change the onClick function like this
onClick() {
this.setState({open: !this.state.open});
}
like this you will need to double click in the second time. or better you can add a button in your pop up to close it

setState in react can only update a mounted or mounting component

I'm getting an error stating that setstate can only be update on mounted or mounting component. I actually want to toggle display of some content. Please help me out. This is the code.
I want to toggle the boolean "show" to true or false. if true, it should show Todolist, if false, it should not show Todolist, instead it should show Footer. Pardon me for framing the question badly. But Please tell me what to do and how to do. Thank you!
import React, {Component} from "react";
import ReactDOM from "react-dom";
import "./index.css";
import TodoList from "./TodoList";
import NavbarTodo from "./NavbarTodo";
import Footer from "./Footer";
import "bootstrap/dist/css/bootstrap.css";
var destination = document.querySelector("#container");
var navdest = document.querySelector(".putnavbarhere");
var clicked=false;
class index extends Component{
constructor() {
super();
this.state = {show: true};
this.handleAbout = this.handleAbout.bind(this);
}
handleAbout(){
this.setState({
show:false
})
clicked=!clicked
if(clicked){
ReactDOM.render(
<Footer />,
document.querySelector("#toast")
)
}
else{
ReactDOM.render(
<p> </p>,
document.querySelector("#toast")
)
};
}
}
var indObj = new index();
ReactDOM.render(
<div>
<TodoList show={indObj.state.show}/>
</div>,
destination
);
ReactDOM.render(
<NavbarTodo clicked={indObj.handleAbout}/>,
navdest
);
What you need is some conditional rendering.
https://reactjs.org/docs/conditional-rendering.html
Your onClick function will toggle this.state.show between true/false.
class Index extends Component {
constructor () {
super()
this.state = {show: true}
}
handleClick () {
this.setState({show: !this.state.show})
}
render () {
return (
<div>
{this.state.show &&
<Todolist component here>
}
{!this.state.show &&
<Footer component here>
}
</div>
)
}
}

Having trouble using React Transition Group first time

Good day! I wrote this code to test the React transition group library and eventually get stuck with the error. The script gets run and I see the data fill form on the page styled but when I click submit button form does not disappear. Error reference description: Failed prop type: The prop timeout is marked as required in CSSTransition, but its value is undefined.
in CSSTransition (at app.jsx:24)
in App (at index.js:7) However transitionAppearTimeot={1500}!
import React, { Component } from 'react';
import CSSTransitionGroup from 'react-transition-group/CSSTransition';
import './app.css';
import Form from './components/Form';
class App extends Component {
constructor() {
super();
this.state = {
mounted: true,
};
this.handleSubmit = this.handleSubmit.bind(this);
};
handleSubmit(event) {
event.preventDefault();
this.setState = {
mounted: false
}
console.log(this.state);
};
render() {
return (
<div className="app">
<CSSTransitionGroup
transitionName="fade"
transitionAppear={true}
transitionAppearTimeout={1500}
transitionEnter={false}
transitionLeave={true}
transitionLeaveTimeout={300}>
{this.state.mounted && <Form onSubmit=
{this.handleSubmit} />}
</CSSTransitionGroup>
</div>
);
}
}
export default App;
The error message is very specific. <CSSTransition> requires a prop timeout but you do not pass anything. Also your other props are not what <CSSTransition> expects.
I guess you are mixing up the old react-transition-group v1 with the new react-transition-group v2. You are using v2 which has a totally different API.

Resources