React - change view when we click on img - javascript

I woudlike to change a view when I click on my img :
const imageClick = () => {
console.log('Click');
}
const Next = () => {
return (
<Heading size="xl" mb="24px">
<br/>
<Row>New Feature Launched</Row>
</Heading>
<Row><img
src={img}
onClick={() => imageClick()}
loading='lazy'
alt=''
/></Row>
<br/>
I wouldike to go there after clicked : http://localhost:3000/view/1

Look into a form of routing like react-router-dom
https://reactrouter.com/web/guides/quick-start
Then you can simply use <Link to="/view1">Home</Link>

Look into my experiment
https://codesandbox.io/embed/simple-route-pgxw4?fontsize=14&hidenavigation=1&theme=dark
full sample above is implementation the react route, you can move from View 1 to View 2

Related

Open Modal in App.js from a button in another component

So I have three components in my app.
App.js
HeroSection.js
Modal.js
The button I have for opening the Modal is in HeroSection. But I need the Modal to render from App.js due to how the styling is structured. When it is opened from HeroSection, it opens in a container that doesn't allow me to position the Modal in the center of the screen (It's in a CSS grid set up). I hope I'm making sense.
My code:
const App = ({ signOut }) => {
return (
<div>
<button onClick={clickOpenAccountModal} className='add-account'>Add Account</button>
{openAddAccountModal && <Modal closeModal={setOpenAddAccountModal} />}
<div className="App">
<div className='nav-pane'>
<SideBar signOut={signOut} />
</div>
<div className='content-pane'>
<MainContent />
</div>
</div>
</div>
);
}
const HeroSection = () => {
// Add Acount Button
const [openAddAccountModal, setOpenAddAccountModal] = useState(false);
const clickOpenAccountModal = () => {
setOpenAddAccountModal(true);
}
// Add Transaction Button
const [openAddTransactionModal, setOpenAddTransactionModal] = useState(false);
const clickOpenTransactionModal = () => {
setOpenAddTransactionModal(true);
}
return (
<div className='hero-section'>
<h1 className='page-title'>Users's Dashboard</h1>
<div className='hero-buttons'>
<button onClick={clickOpenAccountModal} className='add-account'>Add Account</button>
{openAddAccountModal && <Modal closeModal={setOpenAddAccountModal} />}
<button onClick={clickOpenTransactionModal} className='add-transaction'>Add Transaction</button>
{openAddTransactionModal && <Modal closeModal={setOpenAddTransactionModal} />}
</div>
</div>
);
}
const Modal = ({ closeModal }) => {
return (
<div className='modal-background'>
<div className='modal-container'>
<div className='title-container'>
<h2>Add Account</h2>
<button className='exit-button' onClick={() => closeModal(false)}>X</button>
</div>
</div>
</div>
);
}
Main App
How the modal opens in HeroSection
How I need it to open from the button in HeroSection
I tried copying the logic for opening and closing the modal directly to App.js, but to get that to work, I had to put the button used to open the Modal in App.js as well. I need the button to stay in HeroSection and render from App.js
How can I accomplish this?
It is more valid to put the button in the HeroSection component and let the modal be opened in the App.js component. So to start it's the correct approach.
For the implementation there are 2 options:
1-
If the application won't grow to much more components, you can still have the open modal button in the HeroSection component. And that HeroSection component can take a callback function as a prop (for ex openModal) which it can calls when the button is clicked. That way when the function runs you implement the logic for opening/closing the modal in the App.js.
Check solution 1 in react codesandbox
2-
If the application can grow to many components, solution 1 will create unmaintainable code in the long run.
To address this, you can start using a general state management library like redux
When you do that, you can open/close a modal from any component you want without passing any modal specific prop to that component
In general applications, the more correct approach is solution 2. But it can be unnecessary complexity if the application only contains 3 component

window.scrollTo() is not functioning properly in react ionic

I have a listing page in my application. When the user searches for any word the list will be displayed accordingly! To achieve this I am using two components(Let's say search and listing). When the search result is found the array will be passed to another component (i.e. listing component).
Now, the scroll-to-top button is not on the listing component. It is on the searching component. I am calling window.scrollTo(0,0) But nothing is working!
Here is the code:
const scrollToTop = () => {
window.scrollTo(0,0)
}
return (
<div className={`!overflow-y-auto container bg-satin-3 rounded-lg pt-3 pb-6 md:px-3 h-fit xl:pb-3 2xl:pb-2 lg:pb-4`} >
<ComponentCalled to display the listing />
<IonButton
onClick={() => scrollToTop()}
className="float-right"
>
Scroll to Top
</IonButton>
)
I have reuse your code and In my case it's working perfectly as shown below:
scrollToTop = () => { window.scrollTo(0,0); };
return (
<div className="css" >
<p>TOP</p>
<ComponentCalled name="! I'm working"/>
<button
onClick={() => this.scrollToTop()}
className="float-right"
>
Scroll to Top
</button>
</div>
);
https://stackblitz.com/edit/react-ts-vk1fle?file=index.tsx

Text editor value disappears in React Js

I am making a simple accordion and inside each accordion, there is a text editor.
Accordion.js
<div className="wrapper">
{accordionData.map((item, index) => (
<Accordion>
<Heading>
<div
style={{ padding: "10px", cursor: "pointer" }}
className="heading"
onClick={() => toggleHandler(index)}
>
{toggleValue !== index ? `Expand` : `Shrink`}
</div>
</Heading>
<Text> {toggleValue === index && item.content && <EditorContainer />} </Text>
</Accordion>
))}
</div>
Here accordion is made up of as a component. This line {toggleValue === index && item.content && <EditorContainer />} is made to check the accordion clicked and then it loads the content and text editor accordingly.
Complete working example:
https://codesandbox.io/s/react-accordion-forked-dcqbo
Steps to reproduce the issue:
-> Open the above link
-> There will be three accordion
-> Click on any of the accordion, that will change the text from Expand to Shrink
-> Now fill some random text inside the editor then click on the text Shrink
-> Again open the same accordion by clicking Expand
-> Now already entered value is missing
I doubt it happens because every time we expand/shrink, the text_editor.js component gets called and that has the state value like,
this.state = {
editorState: EditorState.createEmpty()
};
Here instead of EditorState.createEmpty(), Should I need to give any other thing?
Requirement:
How can I store the already entered value in the text editor. Even though user clicks expand/shrink, the entered text needs to be remain there in the editor.
Any help is much appreciated.
You are correct, the entered value is missing because you are unmounting the EditorContainer component when its shrinked — that when you expand it again it creates a new editorState which is empty.
2 Possible solutions I could think of.
Move editorState and onEditorStateChange to the Parent component and pass that to EditorContainer. This way, when we unmount the EditorContainer we won't lose the previous editorState because it's on the Parent.
We wrap our EditorContainer inside a div and we'll apply a display style when we toggle between shrink/expand. This way, we are only hiding the EditorContainer not unmounting so its states will retain.
I would choose to implement the 2nd solution because we only have to make changes to our Accordion.js file. In either ways, I would create a new component that would handle the current item. I call it NormalAccordionItem.
const NormalAccordionItem = ({ data }) => {
const [show, setShow] = useState(false);
function toggle() {
setShow((prev) => !prev);
}
return (
<Accordion>
<Heading>
<div
style={{ padding: "10px", cursor: "pointer" }}
className="heading"
onClick={toggle}
>
{show ? "Shrink" : "Expand"}
</div>
</Heading>
<Text>
<div style={{ display: show ? "block" : "none" }}> // notice this
<EditorContainer />
</div>
</Text>
</Accordion>
);
};
Then on our NormalAccordion we'll use NormalAccordionItem.
const NormalAccordion = () => {
return (
<div className="wrapper">
{accordionData.map((data) => (
<NormalAccordionItem data={data} key={data.id} />
))}
</div>
);
};
That's it, check the demo below.
Edit Updated demo to expand NormalAccordionItem one at a time.

What's the correct pattern to change parent state inside a child state in React?

Imagine I have a page "Parent" which conditionally renders a div "Child".
On the click of a button, "Child" opens. To close "Child" one has to click in a X button inside it.
This is how I would do it and in my opinion it looks clean.
const Parent = (props) => {
const [childVisible, setChildVisible] = useState(false);
return (
<>
{childVisible && <Child close={setChildVisible.bind(false)} />}
<button onClick={setChildVisible.bind(true)}>
Open Child
</button>
</>
)
}
const Child = (props) => {
return (
<div>
<p>Im Child</p>
<button onClick={props.close()}> X </button>
</div>
)
}
Since react v16.13.0 react has introduced a warning Warning: Cannot update a component from inside the function body of a different component. and it seems I can't do this anymore.
What's the correct pattern now? I would rather not have a state in both components stating the same thing.
Call back was not properly added .You could do like this onClick={props.close}
While use onClick={props.close()} like this. close() function run on child mount instead of click event
const Child = (props) => {
return (
<div>
<p>Im Child</p>
<button onClick={props.close}> X </button>
</div>
)
}

React js - Show or hide a div

I am trying to show or hide a div in Reactjs using the state value in the CSS style option - display and I am using functions with hooks. I have a button and below the button a div. When i click the button i either want to hide or show the contents in the div based on whether it is currently shown or hidden.
This is the basic test code I have
import React, { useState } from "react";
function hide() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState("none");
return (
<form>
<button
onClick={() => {
setDp("block");
}}
>
Test
</button>
<div style={{ display: dp }}>Test</div>
</form>
);
}
export default hide;
I then use this hide component in my App.js file. When I click the button the new state is assigned but then the page re-renders and the initial state is loaded again almost immediately. How can I go by ensuring the new state is kept? Eventually I will create a function where if the div display or not based on the previous state.
The issue is that the button is inside a <form>. So any click on that button will submit the form and refresh the page.
Can I make a <button> not submit a form?
You need to add a type="button" to your <button>
import React, { useState } from "react";
function Hide() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState(false);
return (
<form>
<button
type="button"
onClick={() => setDp(!dp)}
>
Test
</button>
{dp && <div>Test</div>}
</form>
);
}
export default Hide;
Your code should be something like this, instead of using block and none as style we can use conditional JSX (which is more ideal approach) -:
function Mycomp(){
const[dp, toggleDp] = useState(false);
return(
<form>
<button onClick={()=>{toggleDp(!dp)}}>Test</button>
{dp && <div>Test</div>}
</form>
)
}
export default hide
A better implementation would be to have your state variable TRUE/FALSE value and based on it display the element using a conditional rendering, note e.preventDefault in the button handler to stop the refresh/redirect, here is a working snippet, also a codesandbox:
const { useState, useEffect } = React;
function App() {
return (
<div>
<Mycomp />
</div>
);
}
function Mycomp() {
const [dp, setDp] = useState(true);
return (
<form>
<button
onClick={(e) => {
e.preventDefault();
setDp(!dp);
}}
>
Test
</button>
{dp && <div>Test</div>}
</form>
);
}
ReactDOM.render(<App />, document.getElementById("react-root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

Categories