i am facing issue with using react create portal.
the modal component is not shown on top of parent.
i have two roots in index.html, one is "Modal" and another is "root".
created portal on in Modal is not shown on top of the "root" tree.
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel="stylesheet" type="text/css" href="./style.css" />
</head>
<body>
<div id="modal"></div>
<div id="root"></div>
<script src="App.js"></script>
</body>
</html>
App.js:
import React from "react"
import ReactDOM from "react-dom"
import Modal from "./Modal"
class App extends React.Component
{
constructor(){
super();
this.inputNode = React.createRef();
this.submitHandler = this.submitHandler.bind(this)
}
submitHandler(){
console.log("onclided")
this.inputNode.current.focus();
event.preventDefault();
}
render(){
return(
<div>
<span
onClick={this.submitHandler}>Name</span>
<input
ref={this.inputNode}
>
</input>
<Modal/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById("root"))
Modal.js:
import React from "react"
import ReactDOM from "react-dom"
const modalRoot = document.getElementById('modal');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
<div>hello modal</div>,
this.el,
);
}
}
export default Modal;
can someone tell me what i am doing wrong here ?
in your app.js
import React from "react"
import ReactDOM from "react-dom"
import Modal from "./Modal"
const mainContainer = document.getElementById('root');
const portalContainer = document.getElementById('modal');
class App extends React.Component
{
constructor(){
super();
this.inputNode = React.createRef();
this.submitHandler = this.submitHandler.bind(this);
this.el = document.createElement('div');
}
componentDidMount() {
portalContainer.appendChild(this.el);
}
componentWillUnmount() {
portalContainer.removeChild(this.el);
}
submitHandler(){
console.log("onclided")
this.inputNode.current.focus();
event.preventDefault();
}
render(){
return(
<div>
<span
onClick={this.submitHandler}>Name</span>
<input
ref={this.inputNode}
>
</input>
{ReactDOM.createPortal(
<Modal />,
portalContainer,
);}
</div>
)
}
}
ReactDOM.render(<App/>, mainContainer)
in your Modal.js
import React from "react"
import ReactDOM from "react-dom"
class Modal extends React.Component {
render() {
<div>hello modal</div>
}
}
export default Modal;
I found the out the issue. i didn't provide style position to "Modal" div as : fixed/absolute ,so by default it took static. and both "root" and "modal" are shown up and down.
nothing wrong with my code.
Related
how do I display the result of this code in my browser
code to be displayed in browser
import React from 'react';
import {render} from 'react-dom';
import React from 'react';
import {render} from 'react-dom';
class ManagedControlDemo extends React.Component {
constructor(props){
super(props);
this.state = {message: ""};
}
handleChange(e){
this.setState({message: e.target.value});
}
render() {
return (
<div>
<legend>Type something here</legend>
<input
onChange={this.handleChange.bind(this)}
value={this.state.message}
autoFocus />
<h1>{this.state.message}</h1>
</div>
);
}
}
render(<ManagedControlDemo/>, document.querySelector('#app'));
That last line in your code is telling React to "grab the DOM element in my HTML file with the ID of 'app' and render this ManagedControlDemo component I've made into it."
So note the HTML in the following snippet:
class ManagedControlDemo extends React.Component {
constructor(props){
super(props);
this.state = {message: ""};
}
handleChange(e){
this.setState({message: e.target.value});
}
render() {
return (
<div>
<legend>Type something here</legend>
<input
onChange={this.handleChange.bind(this)}
value={this.state.message}
autoFocus />
<h1>{this.state.message}</h1>
</div>
);
}
}
ReactDOM.render(<ManagedControlDemo/>, document.querySelector('#app'));
<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="app"></div>
Plan - To render <List /> element in index.js. Displays the todo items the user has created.
Error -
./src/components/App.jsx
Attempted import error: './List' does not contain a default export (imported as 'List').
index.js -
import React from 'react';
import ReactDOM from 'react-dom';
import {List, Render} from './components/List';
import App from './components/App';
import '../src/styles.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);
ReactDOM.render(
<Render />
, document.getElementById("list"));
List.jsx -
import react, { useRef } from 'react';
import ReactDOM from 'react-dom';
var todoItems = [];
const inputRef = useRef();
function onClick() {
todoItems.push(inputRef.current.value);
console.log("Pushed item in the array!");
render(inputRef.current.value);
}
function Render(value) {
todoItems.forEach(function a(item) {
<h1>{item}</h1>
});
}
function List() {
return (
<div className="mainbox">
<div className="inputdiv">
<input
type="text"
ref={inputRef}
placeholder="Enter Task..."
className="textbox"
id="taskName"
/>
<button className="button" onClick={onClick}>+</button>
</div>
</div>
);
}
export {List, Render};
I also tried -
export default List;
export {Render};
But it says useRef() cannot be called at the top level.
So I moved the inputRef to the List(), but it says that Render isn't defined.
Thanks!
P.S
After this import/export problem is solved, will the <h1> display?
function Render(value) {
todoItems.forEach(function a(item) {
<h1>{item}</h1>
});
}
EDIT -
index.html -
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link font-family: "Montserrat" , sans-serif;
href="https://fonts.googleapis.com/css?family=McLaren|Montserrat&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="../src/styles.css">
<title>Mandy's Todo-List App!</title>
</head>
<body>
<div id="root">
<div id="list">
</div>
</div>
</body>
</html>
import { useState, useEffect } from 'react';
function App() {
const [value, setValue] = useState('');
const [list, setList] = useState([]);
function handleChange(event) {
setValue(event.target.value);
}
function addTodo() {
setList([...list, value]);
}
useEffect(() => setValue(''), [list]);
return (
<div className='App'>
<input value={value} onChange={handleChange}/>
<button onClick={addTodo}>Add</button>
{list.map((item, index) => <h1 key={index}>{item}</h1>)}
</div>
);
}
export default App;
I have a form to add a category. I expect that when clicking on the add button, there is a notification showing in the corner screen if the input is empty. My idea is returning a Çomponent( or function) contains a toast in handleAddNewCategory() but it's not showing. I know that the library react-bootstrap can do showing toast like this
handleAddNewCategory(){
if(condition)
return toastr.info("message",...);
}
but I don't want to use it for now. Can anyone give me a solution to solve this with using only bootstrap. I'm totally new to Reactjs.
This is some minimal file:
import React, { Component } from "react";
import AddNewCategory from "./AddNewCategory";
import Notification from "./Notification";
class CategoryList extends Component {
constructor(props) {
super(props);
this.state = {
categoryNameInput: "",
categoryDescriptionInput: "",
};
}
...
handleAddNewCategory = () => {
const { categoryNameInput, categoryDescriptionInput } = this.state;
if (categoryNameInput.trim() === "") {
return <Notification message="Please enter category name" />;
}
if (categoryDescriptionInput.trim() === "") {
return <Notification message="Please enter category description" />;
}
};
render() {
return (
<div className="container">
...
<AddNewCategory handleAddNewCategory={this.handleAddNewCategory} />
...
</div>
);
}
}
export default CategoryList;
Notification component
import React, { Component } from "react";
class Notification extends Component {
render() {
const myStyle = {
zIndex: "1001",
position: "absolute",
top: "10px",
right: "10px",
};
return (
<div className="toast col-2" style={myStyle} data-autohide="false">
<div className="toast-header">
<strong className="mr-auto text-primary">Notice</strong>
</div>
<div className="toast-body">{this.props.message}</div>
</div>
);
}
}
export default Notification;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
...
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
$('.toast').toast('show');
});
</script>
</body>
</html>
don't use jquery to show the toast it's not the best practice and instead of conditionally rendering the component what you can do is. just render it ones and then controlled its visibility.
follow the below code:-
Notification component
import React, { Component } from "react";
class Notification extends Component {
render() {
const myStyle = {
zIndex: "1001",
position: "absolute",
top: "10px",
right: "10px",
};
return (
<div hidden={this.props.showToast} className="toast col-2" style={myStyle} data-autohide="false">
<div className="toast-header">
<strong className="mr-auto text-primary">Notice</strong>
</div>
<div className="toast-body">{this.props.message}</div>
</div>
);
}
}
export default Notification;
Notification component usage :-
class CategoryList extends Component {
constructor(props) {
super(props);
this.state = {
categoryNameInput: "",
categoryDescriptionInput: "",
toastMessage:'',
showToast:false
};
}
...
handleAddNewCategory = () => {
const { categoryNameInput, categoryDescriptionInput } = this.state;
if (categoryNameInput.trim() === "") {
this.setState({
toastMessage:'Please enter category name',
showToast:true
})
}
if (categoryDescriptionInput.trim() === "") {
this.setState({
toastMessage:'Please enter category name',
showToast:true
})
}
};
render() {
return (
<div className="container">
<Notification message={this.state.toastMessage} showToast={this.state.showToast}/>;
...
<AddNewCategory handleAddNewCategory={this.handleAddNewCategory} />
...
</div>
);
}
}
export default CategoryList;
here what i do is i initialise the boolean in state and enable it so that toast will be visible and i pass it directly throw props so that whenever your message and boolean changes it automatically reflects in your notification controller.
and to remove the toast just set {showToast} to false whenever you want. and remove the jquery part from your code
I'm new in reactJS, and I am trying to use pure flatpickr (https://flatpickr.js.org , NOT react-flatpickr)
Below is my current code. Any help on how to implement it properly?
import React, { Component } from "react"
import flatpickr from "flatpickr"
export default class Datepicker extends Component<IProps> {
public render() {
flatpickr(".datepicker")
return (
<div>
<input type="text" className="datepicker" />
</div>
)
}
}
flatpickr requires a node or selector passed into it. In React, for referring to the DOM, we use a ref
For handling events and providing other options, you can use the second argument for options.
Here is a demo:
class App extends React.Component {
constructor(props) {
super(props);
this.datePicker = React.createRef();
}
onChange(selectedDates, dateStr, instance) {
console.log(selectedDates);
}
componentDidMount() {
flatpickr(this.datePicker.current, {
onChange: this.onChange
});
}
render() {
return(
<input type="date" ref={this.datePicker} />
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<div id="root"></div>
Example with hooks & Typescript (I had to use useCallback and useRef to make it work):
// Or configure the styling elsewhere.
import 'flatpickr/dist/flatpickr.css';
import flatpickr from 'flatpickr';
import { Instance } from 'flatpickr/dist/types/instance';
export default function Comp() {
const fp1 = useRef() as MutableRefObject<Instance>;
const inputRef = useCallback((node) => {
if (node !== null) {
fp1.current = flatpickr(node, {});
}
}, []);
return (<input type="date" ref={inputRef} />);
}
I'm trying to change the state of one component from another component and my state is not updating, I'm sending back the prop i want to update in my app component but this.setState doesnt work
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import Header from './components/Header';
class App extends Component{
constructor(){
super();
this.state = {
homeLink: "Home"
}
}
onChangeLink(newLink){
this.setState({
homeLink: newLink
});
}
render(){
var user = {
name: "sadf"
}
return(
<div className="container">
<div className="row">
<Header changeLink={this.onChangeLink.bind(this)}/>
</div>
</div>
);
}
}
ReactDOM.render(
<App />,document.getElementById('app')
And here is my header component
import React, {Component} from 'react';
class Header extends Component{
constructor(){
super();
this.state = {
homeLink: 'New Link'
}
}
onChangeLink(){
this.props.changeLink(this.state.homeLink);
}
render(){
return(
<nav className="navbar navbar-default">
<button onClick={this.onChangeLink.bind(this)}>Change Link</button>
</nav>
)
}
}
export default Header
Try something like this:
let newPropValues = {
root: event.target.value
};
this.setState(Object.assign({}, this.state, newPropValues));