ReactJS modal window - javascript

I have no idea how to make my app work.
I have a component ContactAdd that onClick must render component ModalWindow. ModalWindow has a parameter isOpened={this.state.open}. How to control this state from parent component?
import React from 'react';
import ContactAddModal from './ContactAddModal.jsx';
import './ContactAdd.css';
export default class ContactAdd extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<div className="add-contact" onClick={ ??????? }>
<img src="./img/add.png" />
<ContactAddModal/>
</div>
)
}
}
import React from 'react';
export default class ContactAddModal extends React.Component {
constructor(props){
super(props);
this.state = {
show: false,
};
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleCloseModal () {
this.setState({ show: false });
}
render() {
return (
<div className="modal" isOpened={this.state.show}>
<button onClick={this.handleCloseModal}>Close Modal</button>
</div>
)
}

Making the modal a stateless component might be simpler here. The tradeoff being that you would have to handle the closing for every modal, which I think is acceptable. This answer is just an option and by no means an absolute truth.
It could look something like that
export default class ContactAdd extends React.Component {
constructor(props){
super(props);
this.state = {
showModal: true
};
this.hideModal = this.hideModal.bind(this);
}
hideModal() {
this.setState({
showModal: false
});
}
render() {
return (
<div className="add-contact">
<img src="./img/add.png" />
<ContactAddModal handleClose={this.hideModal} isOpened={this.state.showModal} />
</div>
)
}
}
Now the modal:
export default class ContactAddModal extends React.Component {
render() {
return (
<div className="modal" isOpened={this.props.isOpened}>
<button onClick={this.props.handleClose}>Close Modal</button>
</div>
)
}

Related

React todo app, problem with removing task

I'm working on todo app in React and I have weird problem. I created onClick effect on trash icon to remove whole task component. The thing is, sometimes it works (removes whole task), sometimes not (removes only icon). I tried different solutions but to be honest I have no idea why it works like this, this is the same script working differently in different components, for some reason.
main component:
import React from 'react'
import TaskContainer from './TaskContainer.js';
import SingleTask from './SingleTask'
class AppContainer extends React.Component {
constructor(props) {
super(props)
this.state = {
children: [],
numChildren: 0,
newMessage: "What to do next?"
}
this.onAddChild = this.onAddChild.bind(this)
this.handleChange = this.handleChange.bind(this)
}
onAddChild = (msg) => {
let newArray = this.state.children.concat(<SingleTask message={msg} />);
this.setState({ children: newArray });
console.log(this.state.children)
}
handleChange(event) {
this.setState({ newMessage: event.target.value })
}
render() {
return (
<div className="app-container">
<div className="new-task-container">
<input type="text" id="taskInput" defaultValue="What to do next?"
maxlength="50" onChange={this.handleChange} />
<div className="addTask" id="addTask" onClick={
() => {
let text = document.getElementById("taskInput").value;
this.setState({ newMessage: text })
this.onAddChild(this.state.newMessage);
}
}>
<div className="add-button">Add task</div>
</div>
</div>
<TaskContainer>
{this.state.children}
</TaskContainer>
</div>
)
}
}
export default AppContainer
child component
import SingleTask from './SingleTask.js';
function TaskContainer(props) {
return (
<div className="task-container">
{props.children}
</div>
)
}
export default TaskContainer
child's child component - SingleTask
import React from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faTrashAlt } from '#fortawesome/free-regular-svg-icons'
class SingleTask extends React.Component {
constructor(props) {
super(props)
this.state = { active: true }
}
render() {
return (
<div className="singleTask" >
<p>{this.props.message}</p>
<div className="removeTask" onClick={(event) => {
setTimeout(() => {
event.target.parentNode.parentNode.remove()
}, 350)
}
}>
<FontAwesomeIcon icon={faTrashAlt} />
</div>
</div>
)
}
}
export default SingleTask
thanks in advance
I create a CodeSandbox with all the necessary corrections.
https://codesandbox.io/s/upbeat-jang-v7jvm
Piece of advice: When using React is not recommend that you modify the DOM by yourself.

TypeError: Class extends value #<Object> is not a constructor or null in react js

I am trying to over ride some function of a prime react button component but i am getting this error while extending prime react button component class.
Here is my code:
import { Button } from "primereact/button";
class BtnBox extends Button {
constructor(props) {
super(props);
this.renderLabel = this.renderLabel.bind(this);
}
renderLabel() {
return <span>icon</span>;
}
}
class IconButton extends React.Component {
render() {
return (
<div className="icon-button">
<BtnBox {...this.props} />
</div>
);
}
}
export default IconButton;
can you try this form ?
import { Button } from "primereact/button";
class BtnBox extends Button {
constructor(props) {
super(props);
}
render = () => <span>{this.props.name}</span>;
}
class IconButton extends React.Component {
render() {
return (
<div className="icon-button">
<BtnBox name='add item' />
</div>
);
}
}
export default IconButton;
if doesn't suite for you, can you share more detail ?

Accessing variable from different class

How to access the state variable testState from the different class UserAuthentication?
I have tried this without success:
import React from 'react';
import UserAuthenticationUI from './UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render() {
return(
<div>
<UserAuthenticationUI ref={this.userAuthenticationUI} />
<div>
)
}
}
export default App;
How to access this.state.teststate from class UserAuthenticationUI?
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
}
render() {
return(
<div>
<App ref={this.app} />
{console.log(this.state.testState)}
</div>
)
}
}
export default UserAuthenticationUI;
You need to pass it via props.
import React from "react";
import UserAuthenticationUI from "./UserAuthentication/UserAuthenticationUI";
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.setParentState = this.setParentState.bind(this);
this.state = {
testState: "test message"
};
}
setParentState(newStateValue){ // this is called from the child component
this.setState({
testState: newStateValue
})
};
render() {
return (
<div>
<UserAuthenticationUI
stateVariable={this.state.testState}
ref={this.userAuthenticationUI}
setParentState={this.setParentState}
/>
</div>
);
}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from "../App";
class UserAuthenticationUI extends React.Component {
constructor(props) {
super(props);
this.app = React.createRef();
this.onClick = this.onClick.bind(this);
}
onClick(){
const newStateValue = 'new parent state value';
if(typeof this.props.setParentState !== 'undefined'){
this.props.setParentState(newStateValue);
}
}
render() {
const stateProps = this.props.stateVariable;
return (
<div>
<App ref={this.app} />
<div onClick={this.onClick} />
{console.log(stateProps)}
</div>
);
}
}
export default UserAuthenticationUI;
You should think differently.
Try to read the variable via GET methods and set via SET methods.
Do not try to call the variable immediately
Hope this helps.
you can pass it through Props:
import React from 'react';
import UserAuthenticationUI from
'./UserAuthentication/UserAuthenticationUI';
class App extends React.Component {
constructor(props) {
super(props);
this.userAuthenticationUI = React.createRef();
this.state={
testState: 'test message'
}
}
render(){
return(
<div>
<UserAuthenticationUI testState={this.state.testState} />
<div>
)}
}
export default App;
UserAuthenticationUI:
import React from "react";
import App from '../App';
class UserAuthenticationUI extends React.Component
{
constructor(props){
super(props);
}
render(){
return(
<div>
<App/>
{console.log(this.props.testState)}
</div>
)}
}
export default UserAuthenticationUI;
You can access it via props:
<div>
<UserAuthenticationUI testState={this.state.testState} ref={this.userAuthenticationUI} />
<div>
and in UserAuthenticationUI class access it:
<div>
<App ref={this.app} />
{console.log(this.props.testState)}
</div>

Prevent GIF files from reloading when another component uses it in react

I have two components, let's say componentA and componentB. Both component import a .gif file, let's say image.gif. image.gif does not loop, so it should be played once only if it's not updated.
Initially componentA renders image.gif but not componentB. So the image.gif inside componentA is played once. When I render image.gif inside componentB, image.gif inside componentA is played again, which is not wanted.
Can it be done? Thanks!
Edit: Some simple codes for reproducing:
Component A
import image as './image.gif'
export default class componentA extends React.PureComponent {
render() {
return (
<div>
<img src={image} />
</div>
);
}
}
Component B
import image as './image.gif'
export default class componentA extends React.PureComponent {
render() {
return (
<div>
{this.props.show ? <img src={image} /> : null}
</div>
);
}
}
App
import componentA from './componentA.react'
import componentB from './componentB.react'
export default class App extends React.Component {
componentWillMount() {
this.setState({
show: false,
});
}
componentDidMount() {
// ...or some moment when the App thinks componentB should update
this.setTimeout(() => {
this.setState({
show: true,
});
}, 4000);
}
render() {
return (
<componentA />
<componentB show={this.state.show} />
);
}
}
I'd suggest to use a bit more complex (and more flexible) structure:
use static and animated gifs and swap them with javascript.
Like was suggested in similar cases:
Stop a gif animation onload, on mouseover start the activation
JavaScript to control image animation?
As this.setState runs the this.render method, your 2 components are rerendered.
You can try the following :
Component A :
export default class componentA extends React.Component {
render() {
return (
<div>
<img src={image} />
</div>
);
}
}
Component B :
export default class componentB extends React.Component {
constructor () {
super(props)
this.state = { show: false }
}
componentDidMount() {
this.setTimeout(() => {
this.setState({
show: true,
});
}, 4000);
}
render() {
return (
<div>
{this.state.show ? <img src={image} /> : null}
</div>
);
}
}
App :
import componentA from './componentA.react'
import componentB from './componentB.react'
export default class App extends React.Component {
render() {
// Carefull here, you have to return a single `node` in the render method
return (
<div>
<componentA />
<componentB />
</div>
);
}
}

How shared state between separate component in React JS?

I would like to create Dropdown component.
When I click on the DropdownHandler component, I would like to save the state isOpen which can be true or false. If true, this same state is used by <DropdownContent/> to show the content. And by default, the state isOpen is false in <Dropdown /> component
How can I do that please?
App.jsx
import React from 'react';
import {Dropdown, DropdownHandler, DropdownContent} from '../../components/Dropdown/Dropdown.jsx';
class HeaderConnected extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Dropdown>
<DropdownHandler>
<Avatar title="Roberto"></Avatar>
</DropdownHandler>
<DropdownContent>
<li>Menu</li>
<li>Settings</li>
</DropdownContent>
</Dropdown>
</div>
);
}
}
export default HeaderConnected;
Dropdown.jsx
export class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
opened: false
}
}
render() {
return (
<div className="DROPDOWN">
{this.props.children}
</div>
);
}
}
export class DropdownHandler extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="DROPDOWN__HANDLER">
{this.props.children}
</div>
);
}
}
export class DropdownContent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="DROPDOWN__CONTENT">
{this.props.children}
</div>
);
}
}
If you don't want use redux.
You set and control your opend like state of child component and set it to DropdownContent with props. So when you will change opend by click on DropdownHandler, your DropdownContent will recive new propse and call re-render.
import React from 'react';
import {Dropdown, DropdownHandler, DropdownContent} from '../../components/Dropdown/Dropdown.jsx';
class HeaderConnected extends React.Component {
constructor(props) {
super(props);
this.state = {
opened: false
}
}
onClick(){
let condition = this.state.opened;
this.setState({opened: !condition });
}
render() {
return (
<div>
<Dropdown>
<DropdownHandler onClick={this.onClick.bind(this)}>
<Avatar title="Roberto"></Avatar>
</DropdownHandler>
<DropdownContent opened={this.state.opened}>
<li>Menu</li>
<li>Settings</li>
</DropdownContent>
</Dropdown>
</div>
);
}
}
export default HeaderConnected;
I found a solution based on #Andrew answers. Not sure if this is right. But it solves the shared state, only use by Dropdown. I pass the handler and content via props
What do you think?
App.jsx
import React from 'react';
import {Dropdown} from '../../components/Dropdown/Dropdown.jsx';
class HeaderConnected extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Dropdown handler={<Avatar title="Roberto" />}>
<li>Menu</li>
<li>Settings</li>
</Dropdown>
</div>
);
}
}
export default HeaderConnected;
Dropdown.jsx
export class Dropdown extends React.Component {
constructor(props) {
super(props);
this.state = {
opened: false
}
}
render() {
return (
<div className="DROPDOWN">
<div className="DROPDOWN_HANDLER" onClick="...">
{this.props.handler}
</div>
<div className="DROPDOWN_CONTENT">
{this.props.children}
</div>
</div>
);
}
}
Feel free to change the name of the callback "onOpen"
export class Dropdown extends React.Component {
state = {
open: false
}
handleOpen = () => {
this.setState({open: !this.state.open});
}
render() {
return (
<div className="DROPDOWN">
{React.cloneElement(this.props.children, { open: this.state.open, onOpen: this.handleOpen })}
</div>
);
}
}
export class DropdownHandler extends React.Component {
static propTypes = {
open: React.PropTypes.bool.isRequired,
onOpen: React.PropTypes.func.isRequired
}
render() {
return (
<div className="DROPDOWN__HANDLER" onClick={this.props.onOpen}>
{this.props.children}
</div>
);
}
}
export class DropdownContent extends React.Component {
static propTypes = {
open: React.PropTypes.bool.isRequired,
onOpen: React.PropTypes.func.isRequired
}
render() {
// handle visibility here
return (
<div className="DROPDOWN__CONTENT">
{this.props.children}
</div>
);
}
}

Categories