React Modal Component Using Functional Hooks - reactjs

I am working on an app that requires a modal component, this component is currently encompassed with three props that are passed to callback three different modals in the app structure. What I need to achieve is when a button is clicked for the specific modal, add a unique class to the modal wrapper that will identify each modal when clicked, thus manipulating the css with selectors for those modals.
see below:
const NWmodal = (props) => {
return (
<Modal>
<Modalmain data-modal-type="this should pass in a unique id to its modal once button is clicked">
<div>
{props.ejectModal}
</div>
<div>
{props.timeModal}
</div>
<div>
{props.leaveModal}
</div>
<Close>
x
</Close>
</Modalmain>
</Modal>
);
}
<NWmodal
id="timeModal"
timeModal={<NWtimeModal/>} (callback for timemodal component)
/>
<NWmodal
id="leaveModal"
leaveModal={<NWleaveModal/>} (callback for leavemodal component)
/>
<NWmodal
id="ejectModal"
leaveModal={<NWejectModal/>} (callback for ejectmodal component)
/>
function Nav() {
return (
<ul>
<li>
<button
href="javascript:void(0)"
data-modal="timeModal"
onClick={event}>
Time Modal
</button>
</li>
<li>
<button
href="javascript:void(0)"
data-modal="leaveModal"
onClick={event}>
Leave Modal
</button>
</li>
<li>
<button
href="javascript:void(0)"
data-modal="ejectModal"
onClick={event}>
Eject Modal
</button>
</li>
</ul>
);
}

As a disclaimer: I'm still learning this React thing, but the approach I would likely take...
The useRef hook can be used to create variables, which may then in turn be associated with your modals as a reference. eg:
const ejectModalRef = useRef()
<NWmodal id="ejectModal" ref={ejectModalRef} />
The node will be accessible in the onClick JS code as 'ejectModalRef.current'.
(Don't forget to import useRef eg.: import React, { useRef } from "react";
HTH

Related

React - Replacing a component with another on button click

I've two React components, I want a button click in one to replace it entirely with the second.
This is my App Component:
const App = () =>{
const[showMarketing, setShowMarketing] = useState(false);
const[showLanding, setShowLanding] = useState(true)
const toggleViews = () =>{
setShowMarketing(!showMarketing);
setShowLanding(!showLanding);
}
return (
<div>
{showMarketing && <Marketing/>} {showLanding && <Landing toggleViewFn={toggleViews}/> }
</div>
);
}
export default App;
This is the Component that is rendered by default:
const Landing = ({toggleViewFn}) =>(
<div className="shrink-wrapper">
<header className="small-vertical">
<figure className="logo">
<a href="">
<img src={logo} onClick={() => toggleViewFn()}/>
</a>
</figure>
<nav>
</nav>
</header>
</div>
);
This is the component that I want to render on the img click:
const Marketing = () => (
<div>
......Something here
</div>
);
In the current code, the switch happens for a second and the the UI is back to the Landing component. I can't seem to understand why?
I'm new to React, any help appreciated.
The problem is that your <img/> with the onClick is wrapped with an anchor-- when you click the <img/>, the click handler is fired but the anchor click is also registered and the browser navigates. I suspect if you remove the wrapping <a> this will work as expected.
Ultimately, if you are trying to use this for routing, you'd be better off leveraging a library like React Router; while you could try to manage your own routing on your own, it can be complex and is rife with accessibility pitfalls (for instance, using anchors with empty hrefs to wrap items with onClick handlers is not particularly accessible). Hope this helps.

The Use of "Navigate(-1)" Fails to Return to Previous Location in Gatsby

I am trying to create a simple "Back" button in Gatsby that returns the the previous page and retains the scroll position. This already happens when using the browser back button, but I'm struggling to produce a custom one. I've read in the Reach Router docs that you can add -1 as an argument to the navigate function to return to previous locations, but It instead throws the number value into the url and gives me a 404. Can someone give me an idea of what I've done wrong? Or if anyone else has managed to make a functional back button for Gatsby projects?
Here is my code-
import React from 'react';
import { graphql, navigate } from 'gatsby'
import Img from "gatsby-image"
import "./design.scss"
const designTemplate = (props) => {
return (
<section className="design">
<div className="design__container">
<h2 className="design__title">
{props.data.design.title}
</h2>
<Img className="design__image" fluid={props.data.design.localImage.childImageSharp.fluid} />
<p className="design__summary">
{props.data.design.summary}
</p>
</div>
<button onClick={navigate(-1)}>Go Back</button>
</section>
);
}
The issue you're having here is just that you didn't define a callback function for your onClick handler.
Instead of this:
<button onClick={navigate(-1)}>Go Back</button>
…you want to do this:
<button onClick={() => { navigate(-1) }}>Go Back</button>
Your onClick must have a callback(arrow function) like this
onClick={()=>{navigate(-1)}}
not
navigate(-1)

Avoid component update while changing state vaiable

Background
I have a React component which includes further two more components. I component includes a chart(build with react-charts) and the other is a simple input field. I initially make not visible but it become visible when someone clicks icon over there.
Issue, child rerenders when state changes
Now the problem is whenever I toggle this input field it automatically refreshes my graph. In fact when I type into my input field it also refreshes the graph. I think it rerenderes the graph as I update the state variable. I want to stop this behavior. Any suggestions on how can I do this.
Component Screenshot(https://i.imgur.com/zeCQ6FC.png)
Component Code
<div className="row">
<DealGraph ref={this.dealRef} />
<div className="col-md-4">
<div className="row">
<div style={style} className="col-md-12 bg-white border-radius-10 default-shadow">
<h3 className="sub-heading roboto" style={border}>
Create Deals
</h3>
<input
type="text"
name="deal"
className="form-control mgt-30"
value="Deal One"
readOnly
/>
<button
type="button"
onClick={this.showAddBlock}
style={button}
className="golden-button create-deal-button"
>
<i className="fa fa-plus"></i>
</button>
{addDealStatus ? (
<div className="col-md-12 add-deal-box pd-0-0">
<input
type="text"
className="form-control mgt-30 mgb-10"
name="add-deals"
placeholder="Add Deals"
/>
<button type="button" className="golden-button flex all-center">
Add
</button>
</div>
) : null}
</div>
</div>
</div>
</div>
Toggle function
showAddBlock=() => {
this.setState({addDealStatus:!this.state.addDealStatus})
}
use PureComponent
To stop a child component rerendering from it parent you should make the child a pure component.
import React from 'react';
class DealGraph extends React.PureComponent { // notice PureComponent
render() {
const { label, score = 0, total = Math.max(1, score) } = this.props;
return (
<div>
/* Your graph code */
</div>
)
}
}
Use the { pure } HOC from Recompose
You can use a functional component that is wrapped in the pure HOC from recompose
import React from 'react';
import { pure } from 'recompose';
function DealGraph(props) {
return (
<div>
/* Your graph code */
</div>
)
}
export default pure(DealGraph); // notice pure HOC
A quick solution would be to move the input to an own component.
A more sophisticated solution is adapting the shouldComponentUpdate function in your DealGraphcomponent like stated here React: Parent component re-renders all children, even those that haven't changed on state change
By Default while rendering every component react checks for shouldComponentUpdate .React Components dont implement shouldComponentUpdate by default.So either we can implement a shouldComponentUpdate. Or Make the child class as a pure component.

React router not rendering the component on click of a Array item

I'm creating a component which has array of items and showing them on one page using map function.
Need help on how I can show a detail view of a item by updating route value dynamically based on the item I clicked.
Currently when I click on a item know more though the url change to some wrong value I don't see any change in the page.
Component:
{location[area].map((item, index) =>
<div key={index} className="col-md-4 mt-3">
<div className="card">
<div className="card-body">
<h5 className="card-title">{item.title}</h5>
<p className="card-text">{item.description}</p>
<Link to={'/view/${item.title}'} onClick={() => addDetail(item)} className="btn btn-primary">Know more</Link>
</div>
</div>
</div>
)}
Router:
<Route path='/view/:id' exact component={DetailPage} />
DetailPage Component:
class DetailPage extends Component {
render() {
const selectedItem = this.props.selectedItem;
return(
<div>
<DetailedView selectedItem={this.props.selectedItem} />
</div>
);
}
}
Result Anchor Tag:
<a class="btn btn-primary" href="/view/${item.title}">Know more</a>
Onclick result url:
http://localhost:3000/view/$%7Bitem.title%7D
You need to use backticks for the to prop of your Link components so that template literals will be used and the variable will be inserted into the string.
<Link
to={`/view/${item.title}`}
onClick={() => addDetail(item)}
className="btn btn-primary"
>
Know more
</Link>
Well,As #tholle suggested use template literal.Your route seems fine, just make use of react life cycle method componentWillReceiveProps in the Detail Page Component.Here is the code
class DetailPage extends Component {
componentWillReceiveProps(nextProps){
if(this.props.match.params.id !== nextProps.match.params.id){
//make a call with updated nextProps.match.id or filter the existing data store
with nextProps.match.id
}
}
render() {
const selectedItem = this.props.selectedItem;
return(
<div>
<DetailedView selectedItem={this.props.selectedItem} />
</div>
);
}
}

react Rating component not working as expected

I am trying to make the react rating component work but I am getting some strange behaviour. When I make a selection (3 stars for example) the stars don't stay selected. This is how I want to be able to do it: I have a parent component (handles the state, etc.) that calls a child component. Then the child component makes a call to the React-Rating component. The reason I want to do this is because I want to be able to make these rating components usable in different places; therefore no code duplication would be needed. Below is my code.
//THIS IS FROM MY PARENT COMPONENT.
<Ratings onClick={newRating => this.setState({ rating: newRating })}/>
//THIS IS MY CHILD COMPONENT THAT CALL THE RATING LIBRARY.
export const Ratings = ({ rating, onClick}) => (
<div className={styles.rateContainer}>
<Rating
empty={`fa fa-star-o fa-2x ${styles.rating}`}
full={`fa fa-star fa-2x ${styles.rating}`}
onClick={onClick}/>// THIS IS TO OVERRIDE THE onClick event on the react library
<div>
<p className={styles.comments} />
</div>
</div>
);
export default Ratings;
What am I doing wrong?
I stored my rating as a part of state and then set the initialRate to reflect that state. That made my ratings stick. I think this might be what you are looking for.
<div className={styles.rateContainer}>
<Rating
empty={`fa fa-star-o fa-2x ${styles.rating}`}
full={`fa fa-star fa-2x ${styles.rating}`}
onClick={ (rating) => this.setState({rating: rating})}
intialRate={this.state.rating}
<div>
<p className={styles.comments} />
</div>
</div>

Resources