React - hide content with button - javascript

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;

Related

Display a message in semantic ui only after a button is clicked

In Semantic UI, a message can be visible
<Message visible>You can always see me</Message>
or hidden.
<Message hidden>You can't see me</Message>
I have a button that when clicked gets an API response, that then fills a Message with text. I only want to see the Message after clicking the button, because until then it is just an empty box at the bottom of the screen. How can I implement this in my function?
import React, { useState } from 'react';
import { Button, Header, Message} from 'semantic-ui-react'
export default function Writer() {
const [titleText, setTitleText] = useState('');
const getResponse = () => {
//Does Some Stuff
}).then((response) => {
setTitleText(response.data.choices[0].text)
})
return (
<div>
<Button onClick={getResponse}></Button>
<Message>
<Header
icon textAlign='center'
content={titleText}
/>
</Message>
</div>
)
}
I tried to set a variable
var visibility = 'hidden'
and set visibility = 'visible' inside the function, then writing <Message {visibility}? but it did not work. Any recommendations please?
In Semantic-UI-React the visible & hidden are boolean flags. So you need to pass in a Boolean value. & because you need it to be done based on titleText you can simply use the length property.
import React, { useState } from 'react';
import { Button, Header, Message} from 'semantic-ui-react'
export default function Writer() {
const [titleText, setTitleText] = useState('');
const getResponse = () => {
//Does Some Stuff
}).then((response) => {
setTitleText(response.data.choices[0].text)
})
return (
<div>
<Button onClick={getResponse}></Button>
<Message visible={titleText.length > 0} hidden={titleText.length === 0}>
<Header
icon textAlign='center'
content={titleText}
/>
</Message>
</div>
)
}

Modal component does not render on a custom button component

I am trying to render a custom and dynamic modal on button clicks. For example, when a "Game" button is clicked, I would like a modal to render with specfics about the game and when a "Bank" button is clicked, I would like the modal to populate with specfics about a bank.
First, when I add an onClick function to a custom button component, the modal does not render. However, when I put the onClick function on a regular button, the modal does render. How can I simply add an onClick function on any component to render a dynamic modal?
Second, I would like to populate each modal with differnet data. For example, a "Game" button would populate the modal with a title of "Game" and so on. I'm using props to do this, but is that the best solution?
Here is the code I have so far, but it is broken when I add the onClick function to components.
// Navbar.js
import { ModalContext } from '../contexts/ModalContext'
function Navbar() {
const [showModal, updateShowModal] = React.useState(false)
const toggleModal = () => updateShowModal((state) => !state)
return(
<ModalContext.Provider value={{ showModal, toggleModal }}>
<Modal
title="Title"
canShow={showModal}
updateModalState={toggleModal}
/>
</ModalContext.Provider>
)
// does not render a modal
<Button
onClick={toggleModal}
type="navItem"
label="Game"
icon="windows"
/>
// render a modal
<button onClick={toggleModal}>Show Modal</button>
)
}
import { ModalContext } from '../contexts/ModalContext'
// Modal.js
const Modal = ({ title }) => {
return (
<ModalContext.Consumer>
{(context) => {
if (context.showModal) {
return (
<div style={modalStyles}>
<h1>{title}</h1>
<button onClick={context.toggleModal}>X</button>
</div>
)
}
return null
}}
</ModalContext.Consumer>
)
}
// modalContext.js
export const ModalContext = React.createContext()
// Button.js
function Button({ label, type = 'default', icon }) {
return (
<ButtonStyle buttonType={type}>
{setIcon(icon)}
{label}
</ButtonStyle>
)
}
First problem:
I think the onClick prop of the <Button> component is not pointing to the onClick of the actual HTML button inside the component.
Could you please check that? And if you think It's been set up in the right way, then can you share the code of the component?
Second Problem
Yes, there's another way to do that. And I think it's React Composition. You can build the modal as the following:
<Modal
showModal={showModal}
updateModalState={toggleModal}
>
<div className="modal__header">{title}</div>
<div className="modal__body">{body}</div>
<div className="modal__footer">{footer}</div>
</Modal>
I think this pattern will give you more control over that component.
Issue
You are not passing the onClick prop through to the styled button component.
Solution
Given style-component button:
const ButtonStyle = styled.button``;
The custom Button component needs to pass all button props on to the ButtonStyle component.
// Button.js
function Button({ label, type='default', icon, onClick }) {
return (
<ButtonStyle buttonType={type} onClick={onClick}>
{setIcon(icon)}
{label}
</ButtonStyle>
)
}
If there are other button props then you can use the Spread syntax to collect them into a single object that can then be spread into the ButtonStyle component.
// Button.js
function Button({ label, type = 'default', icon, ...props }) {
return (
<ButtonStyle buttonType={type} {...props}>
{setIcon(icon)}
{label}
</ButtonStyle>
)
}
Second Question
For the second issue I suggest encapsulating the open/close/title state entirely in the modal context provider, along with the Modal component.
Here's an example implementation:
const ModalContext = React.createContext({
openModal: () => {},
});
const Modal = ({ title, onClose}) => (
<>
<h1>{title}</h1>
<button onClick={onClose}>X</button>
</>
)
const ModalProvider = ({ children }) => {
const [showModal, setShowModal] = React.useState(false);
const [title, setTitle] = React.useState('');
const openModal = (title) => {
setShowModal(true);
setTitle(title);
}
const closeModal = () => setShowModal(false);
return (
<ModalContext.Provider value={{ openModal }}>
{children}
{showModal && <Modal title={title} onClose={closeModal} />}
</ModalContext.Provider>
)
}
Example consumer to set/open a modal:
const OpenModalButton = ({ children }) => {
const { openModal } = useContext(ModalContext);
return <button onClick={() => openModal(children)}>{children}</button>
}
Example usage:
function App() {
return (
<ModalProvider>
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<OpenModalButton>Modal A</OpenModalButton>
<OpenModalButton>Modal B</OpenModalButton>
</div>
</ModalProvider>
);
}
Demo

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

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

Why useEffect isn't changing the paragraph?

I'm studying React useEffect hook and trying to use it in a simple example. I want to have the paragraph showing modal as an effect that happens ONLY when the modal is open, and disappears when the modal is closed.
So I have only the View component in index.js, and that's the component:
import React from 'react';
import Modal from './Modal.js';
const View = () => {
let [showModal, setModal] = React.useState(false)
React.useEffect(() => {
document.getElementById('alerta').innerHTML = 'Showing modal'
return () => {
document.getElementById('alerta').innerHTML = ''
}
}, [showModal])
return(
<>
<button onClick={() => {setModal(!showModal)}}>
Show modal
</button>
<Modal showModal={showModal} setModal={setModal}/>
<p id="alerta" ></p>
</>
)
}
export default View;
Modal.js looks like this
import React from 'react';
const Modal = (props) => {
if(props.showModal){
return(
<div>
<h1>Showing modal</h1>
<button onClick={() => props.setModal(false)}>Close</button>
</div>
)
}else {
return null;
}
}
export default Modal;
As explained in the documentation, my effect returns a function that should run when the effect is cleaned, that's when the modal is closed. I also have specified that I want to run the effect only when something changes in my showModal state.
If I insert a console.log(showModal) inside my effect function, I'll see its value changing when the modal is shown or when it's closed, but the problem is, the paragraph is ALWAYS there.
Why is that happening?
Every time the effect hook runs, it will populate the paragraph:
React.useEffect(() => {
document.getElementById('alerta').innerHTML = 'Showing modal'
return () => {
document.getElementById('alerta').innerHTML = ''
}
}, [showModal])
Every render, if showModal changes, no matter what it changes to:
The cleanup from the prior render will run, clearing the content
The effect for the new render will run, populating the content
So it will always look populated.
The right way to do this would be to put the toggling logic into the JSX and use state instead of DOM methods:
const View = () => {
let [showModal, setModal] = React.useState(false)
return(
<React.Fragment>
<button onClick={() => {setModal(!showModal)}}>
Show modal
</button>
<div style={{ display: showModal ? 'block' : 'none' }}>modal here...</div>
<p id="alerta">{showModal ? 'Showing modal' : ''}</p>
</React.Fragment>
)
}
ReactDOM.render(<View />, document.querySelector('.react'));
<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>
<div class='react'></div>

Moving div into specific part of the page when its clicked

So here I have an App component where I have rendered the Navbar. I have a toggle function and logic on outside Click using useRef/useEffect. My intentions are when I click on the div where Navbar is located, I want to copy that div/img to specific part of the page using Css, and when it's moved I want in that copy text/h4 to be removed/dissapear. I would appriciate any help. Thanks
function App() {
const [isNavbarOpen, setIsNavbarOpen] = useState(false)
const navbar = useRef()
const openNavbar=()=>{
setIsNavbarOpen(true)
}
const closeNavbar=()=>{
setIsNavbarOpen(false)
}
const handleNavbar=(e)=>{
if(navbar.current && !navbar.current.contains(e.target)){
closeNavbar()
}
}
useEffect(()=>{
document.addEventListener('click', handleNavbar)
return() =>{
document.removeEventListener('click', handleNavbar)
}
},[])
return (
<>
<div className='smallProjects__container'
onClick={() => setIsNavbarOpen(!isNavbarOpen)} ref={navbar}>
<img
src="./images/icons/folr.png"/>
<h4>Navbar</h4>
{isNavbar? <Navbar closeNavbar={closeNavbar} />: null}
</div>
</>
);
}
export default App;

Categories

Resources