How can I append a React component to an html element i? - javascript

I am using the modal library winbox. It works well if use simple html and javascript. But I can't append a React node to it.
The modal has a html parameter, that accept an html string such as div.innerHTML = <div>hello</div> . The code source is: this.body.innerHTML = html;.
So adding a classic React element makes the modal crash. The only solution I found is to use react-dom's renderToString method: html: renderToString(children). But the component is not dynamic anymore (no state update, etc.).
I also tried to surround React.renderDOM by a div inside the modal and attach the component to it, as the app is attached to index.js's #root div.
html: <div id="modal">
{render(
<div children={content} />,
document.querySelector("#modal")
)},
</div>
My question is thus: how to pass a dynamic React component to the body of this modal?
Here is my code:
import React from "react";
import useModal from "./useModal";
const Counter = () => {
const [count, setCount] = useState(1);
return (
<div>
The count is {count}
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
};
export default function App() {
const [open, setOpen] = useState(false);
useModal(open, setOpen, <Counter />);
return (
<div id="#hi">
<button onClick={() => setOpen(!open)}>toggle</button>
</div>
);
}
// useModal
import WinBox from "winbox/src/js/winbox.js";
import "winbox/dist/css/winbox.min.css";
import React from "react";
import { render } from "react-dom";
export default function useModal(open, onToggle, content) {
const modal = open
? new WinBox({
title: "Hello",
max: true,
html: content, // INSERT DYNAMIC COMPONENT HERE
onclose: () => onToggle(false)
})
: null;
return modal;
}
Thank you!

You can use winbox-react package from npm. winbox-react npm link Example code is given below. Youcan use normal jsx as children of the WinboxReact component.
const Hero = () => {
const [show, setShow] = useState(false)
const clickHandeler = () => {
setShow(!show)
}
return (
<div className='text-center'>
{show && (
<WinboxReact
onClose={clickHandeler}
background='linear-gradient(90deg, rgba(49,36,239,1) 0%, rgba(67,0,168,1) 100%)'
><h1>Hello</h1></WinboxReact>
)}
<button onClick={clickHandeler} className='btn btn-custom btn-lg mt-4'>
Show Example
</button>
</div>
)
}
export default Hero

Related

Passing Variables to/from Modal

I implemented a Modal which uses a custom Hook in my App that should function as a login mask for a WiFi network. So far the Modal is working and I also already managed to pass the name of the selected SSID to it. However I'm struggling with getting back a variable into my other component from where I launched the modal.
Modal.js:
import React from 'react';
import { createPortal } from 'react-dom';
const Modal = ({ isShowing, connect, ssid, hide }) => isShowing ? createPortal(
<React.Fragment>
<div className="modal-overlay" />
<div className="modal-wrapper" aria-modal aria-hidden tabIndex={-1} role="dialog">
<div className="modal">
<div className="modal-header">
<button type="button" className="modal-close-button" data-dismiss="modal" aria-label="Close" onClick={hide}>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
<p>Connect to: {ssid}</p>
<label>
<form onSubmit={connect}>
<input
id="password"
name="Password"
type="password"
value={"password"}
/>
<button type="submit">Connect</button>
</form>
</label>
</div>
</div>
</div>
</React.Fragment>, document.getElementById("modal")
) : null;
export default Modal;
useModal.js:
import { useState } from 'react';
const useModal = () => {
const [isShowing, setIsShowing] = useState(false);
const [password, setPassword] = useState("password");
function toggle() {
setPassword("HOW");
setIsShowing(!isShowing);
}
return {
password,
isShowing,
}
};
export default useModal;
Settings.js:
import React from "react";
import { useState, useEffect } from "react";
import Modal from "../../components/Modal";
import useModal from "../../components/useModal";
const electron = window.require('electron');
const { ipcRenderer } = electron;
const Settings = ({ reqReload }) => {
const [wifiList, setWifiList] = useState([{ id: "", ssid: 'No Networks available' }]);
const [ssidSelected, setSsidSelected] = useState("127.0.0.1");
const { isShowing, toggle } = useModal();
const updateWifi = (event, args) => {
setWifiList(args);
};
function openDialogue(ssid) {
setSsidSelected(ssid);
toggle();
};
/*
function connectWifi(password) {
console.log("Aktuelles Passwort: ", password);
toggle();
}
*/
useEffect(() => {
ipcRenderer.send('updateWifi');
ipcRenderer.on('wifi_list', updateWifi);
return function cleanup() {
ipcRenderer.removeListener('wifi_list', updateWifi);
};
}, []);
return (
<div className="settings">
<Modal
isShowing={isShowing}
connect={connectWifi}
ssid={ssidSelected}
hide={toggle}
/>
<div className="settings__header">
<h2></h2>
</div>
<div className="settings__body">
<div className="settings__connections">
<div className="settings__connections__wifi">
<p><i>Available Wifi-Networks:</i></p>
<div className="settings__connections__wifi__list">
{wifiList.map((item, i) => (
<div className="settings__connections__wifi__list__item" key={i}>
<button className="selectNetworkButton" type="button" onClick={() => openDialogue(item.ssid)}>{item.ssid}</button>
</div>
))}
</div>
</div>
</div>
</div>
</div>
)
};
export default Settings;
The code above already contains some things I tried. As stated before, passing the SSID to the modal worked, but I dont have a clue how to get the password back to Settings.js to handle the data there.
I'd be happy if someone can point me in the right direction!
in order to get back a variable from a child component, you can have the variable you would like to get back as a state in your parent component:
const [yourVariable, setYourVariable] = useState('')
then pass setYourVariable as a props to your modal.
this way you can set youVariable from inside the modal component, and get back its value this way :
// inside modal component
setYoutVariable(...)
I stumbled over another article just now and it seems like using a stateless component as my model leads to a dead end. Will have to convert it to a stateful component in order to extract the data from the form.

Data not being passed from parent to child. (ReactJS)

I am currently making a Trello Clone. It has been going well so far and I've had a lot of help from everyone here, so thank you!
My current issue is that I am trying to pass the state of modalData in App.js to <ModifyModal />.
I have tried researching and Googling, and even re-writing functions and creating new ones. However, nothing had worked. I know that the state is being updated with the correct text since I made the title from Trello Clone! to {modalData} and it worked. I want the data of modalData to be passed from App.js to <ModifyModal />.
Edit: Made a functional component and it is still showing undefined for the data.
App.js:
import React, { Component } from 'react';
import './App.css';
import Todobox from './Todobox';
import ModifyModal from './ModifyModal';
import Item from './Item';
const Widget = ({parentCallback2}) => <Todobox parentCallback2={parentCallback2}/>
const Widget2 = () => <ModifyModal />
class App extends Component {
constructor(props){
super(props);
this.handleCallback = this.handleCallback.bind(this);
this.state={
elements: [],
modal: [],
modalData: null
}
}
// Creates new element box
handleNewElement = () => {
const newElement = [...this.state.elements, Widget];
this.setState({
elements: newElement
});
}
handleCallback = (itemWidget, itemData) =>{
const newModal = [...this.state.modal, itemWidget];
const newData = itemData;
this.setState({
modal: newModal,
modalData: newData
});
}
render() {
const { elements, modal, modalData } = this.state;
return (
<>
<div className='page-container'>
<div className='header'>
<a className='header-title'>{modalData}</a>
<a className='header-button' onClick={this.handleNewElement.bind(this)}>Create a list</a>
</div>
<div className='element-field'>
{elements.length !== 0 &&
elements.map((Widget, i) => <Widget key={i} parentCallback2={this.handleCallback}/>)}
</div>
</div>
{modal.length !== 0 &&
modal.map((Widget2, i) => <Widget2 key={i} itemDataToChild={modalData} />)}
</>
);
}
}
export default App;
ModifyModal.jsx:
import React from "react";
import { useState } from "react";
import trash from './trash_can.png';
import './App.css'
function ModifyModal({ itemDataToChild }){
const [hideModal, setHideModal] = useState(false);
const [content, setContent] = useState(itemDataToChild);
const handleCancel = () =>{
setHideModal(true);
}
return(
<>
<div className={`modify-modal-container ${hideModal ? 'modify-modal-container-hide' : ''}`}>
<div className='modify-modal'>
<a className='modify-title'>{content}</a>
<textarea className='modify-input' />
<div className='modify-buttons'>
<a className='modify-btn' id='modify-update-btn'>Update</a>
<a className='modify-btn' id='modify-cancel-btn' onClick={handleCancel}>Cancel</a>
<img src={trash} id='modify-delete'/>
</div>
</div>
</div>
</>
)
}
export default ModifyModal;
Any help is appreciated since I am new to this. :)
The problem is when you declared and initialized Widget2.
const Widget2 = () => <ModifyModal />
What is actually happening under the hood is that Widget2 received a function which returns a JSX.Element, it didn't actually become ModifyModal, the functional component.If you look at the line above is actually doing right.
const Widget = ({parentCallback2}) => <Todobox parentCallback2={parentCallback2}/>
There is 2 solution for this.
you can do just as Widget.
const Widget2 = ({itemDataToChild}) => <ModifyModal itemDataToChild={itemDataToChild}/>
Which I think should be the best approach since you can just rename your imports if was exported as default, and deleting the line const Widget2 = () => <ModifyModal />
import Widget2 from './ModifyModal';
Keeping in mind that the second approach would result error if used for Named Exports. Imports Reference.
For broad your understanding of JSX element and functional component I recommend take a look at their official documentation.
JSX, Components and Props

React - hide content with button

i'm new here. I got a problem with a task. I want a button that if you press it hides some content, a string in this case. If the content is hidden the button must change the text inside it,
and it must say "show" and instead of hiding it shows the content
previously hidden. If the content is already displayed, the button text will be "hide".
I don't understand how to use if statement
...
import React { useState } from "react";
function App() {
const [hideText, setHideText] = useState(false);
const onClick = () => setHideText(false);
return (
<div>
<button onClick={onClick}>Click me</button>
{hideText ? <Text /> : null}
</div>
);
}
const Text = () => <div>I will disappear, true Magic</div>;
export default App;
...
I don't know if I correctly understood your needs.
I changed the variable name to be more meaningful :)
Now the button shows Hide when the text is visible and Show when it's hidden. Clicking the button changes the state.
import React { useState } from "react";
function App() {
const [isTextHidden, setTextHidden] = useState(true);
const onClick = () => setTextHidden(!isTextHidden);
return (
<div>
<button onClick={onClick}>{isTextHidden ? 'Show' : 'Hide'}</button>
{!textHidden ? <Text /> : null}
</div>
);
}
const Text = () => <div>I will disappear, true Magic</div>;
export default App;
import React { useState } from "react";
function App() {
const [isVisible, setVisible] = useState(true);
const onClick = () => setVisible(!isVisible);
return (
<div>
<button onClick={onClick}>{isVisible? 'Hide' : 'Show'}</button>
{isVisible? <Text /> : null}
</div>
);
}
const Text = () => <div>I will disappear, true Magic</div>;
export default App;

Create and download image of a react component without rendering it

My use case is simple. I have a react component that takes some props and renders something. Now I want to download it as an image without rendering it basically not showing it to the user.
I have tried html2canvas and react-component-export-image. In both of these libraries, I managed to capture the screenshot but both of them required me to render the component.
I used code from this page for react-component-export-image https://www.npmjs.com/package/react-component-export-image
Suppose the following is my component
const Component1 = ({ reference }) => {
return (
<div ref={reference} >
<div className="share-cause-header">
Some header stuff
</div>
<div className="share-cause-body">
some body stuff
</div>
<div className="share-cause-footer">
some footer stuff
</div>
</div>
);
};
Now on another Component2, I want to send some props to my Component1 and then download that component as an image without showing anything to the user. A user should only see the download button and the downloaded image
const Component2 = () => {
const shareButtonImageDownload = (e) => {
e.stopPropagation();
console.log("Hi there");
};
return (
<div >
<button onClick={shareButtonImageDownload } ></button>
</div>
);
};
If the component is not visible, then you can't take a screenshot of it. But you can bring them out of the visible view, like this:
https://codesandbox.io/embed/laughing-http-w3ndr?fontsize=14&hidenavigation=1&theme=dark
import {
exportComponentAsJPEG,
exportComponentAsPDF,
exportComponentAsPNG
} from "react-component-export-image";
import React, { useRef } from "react";
const ComponentToPrint = React.forwardRef((props, ref) => (
<div ref={ref} style={{ marginTop: "-50px" }}>
<div className="share-cause-header">Some header stuff</div>
<div className="share-cause-body">some body stuff</div>
<div className="share-cause-footer">some footer stuff</div>
</div>
));
const MyComponent = () => {
const componentRef = useRef();
return (
<React.Fragment>
<ComponentToPrint ref={componentRef} />
<button onClick={() => exportComponentAsJPEG(componentRef)}>
Export As JPEG
</button>
<button onClick={() => exportComponentAsPDF(componentRef)}>
Export As PDF
</button>
<button onClick={() => exportComponentAsPNG(componentRef)}>
Export As PNG
</button>
</React.Fragment>
);
};
export default MyComponent;

React / Functional component / Conditional render on callback / Not Working

Why this does not work ?
import React from 'react';
function Room() {
let check = null;
const ibegyouwork = () => {
check = <button>New button</button>;
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{check}
</div>
);
}
export default Room;
And this works fine ?
import React from 'react';
function Room() {
let check = null;
return (
<div>
<button>No need for this button because in this case the second button is auto-displayed</button>
{check}
</div>
);
}
export default Room;
Basically I try to render a component based on a condition. This is a very basic example. But what I have is very similar. If you wonder why I need to update the check variable inside that function is because in my example I have a callback function there where I receive an ID which I need to use in that new component.
The example that I provided to you is basically a button and I want to show another one when I press on this one.
I am new to React and despite I searched in the past 2 hours for a solution I couldn't find anything to address this issue.
Any tips are highly appreciated !
Your component has no idea that something has changed when you click the button. You will need to use state in order to inform React that a rerender is required:
import React, {useState} from 'react'
function Room() {
const [check, setCheck] = useState(null);
const ibegyouwork = () => {
setCheck(<button>New button</button>);
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{check}
</div>
);
}
export default Room;
When you call setCheck, React basically decides that a rerender is required, and updates the view.
The latter is working because there are no changes to the check value that should appear on the DOM.
If check changes should impact and trigger the React render function, you would want to use a state for show/hide condition.
import React from 'react';
const Check = () => <button>New button</button>;
function Room() {
const [show, setShow] = React.useState(false);
const ibegyouwork = () => {
setShow(true);
}
return (
<div>
<button onClick={ibegyouwork}>Display my button now !!!!</button>
{show && <Check />}
</div>
);
}
export default Room;

Categories

Resources