Update dom without refresh the page in react 16 - reactjs

So, I've been looking for a way to render this img tag on my dom without refresh the screen. But I didn't find a definitive answer on how to do that! I mean, in a natural way, with react library and without change a lot of things.
So, when I click this div, it calls a method
<div ref={(ref) => this.refProjectImageCenter = ref} onClick={(e) => this.selectImage(e, this.refProjectImageCenter)} >
<img src="images/projects/new-account.png" alt="new account" />
</div>
And in this method, I update my state with a new img element (not sure if it's the best way to do it tho)
selectImage(e: any , el: HTMLDivElement)
{
e.preventDefault(); // This is not working
this.setState({ selected_img: <img src={el.children[0].getAttribute("src")} /> });
}
And the state will update this part of the DOM
<div className="image detail">
{this.state.selected_img}
</div>
It renders the img indeed, but the page flashes(refresh), and I want to do that asynchronously. It's possible to do that with react? If it's not, how everybody is doing it right now? Thanks a lot.

I found the problem Henry and Shubham. I was updating the css class of the main html tag:
this.refMasterDOM.classList.remove("active");
Inside the method componentWillUpdate(). I removed this line and it stopped refreshing the page with sestate command. Although I don't know why.

Related

Screen reader not reading the Headings when navigating back - React JS

I want to make the headings (H1 tag) to be auto focused on page load so the screen reader can read the headings.
With the below code I made it work as expected.
<fieldset> <h1 role="alert"> <a id="specialfocusable" tabIndex={-1}> Component A </a> </h1> </fieldset>
My app is like a stepper, were we move from component A to Component B similarly Component B to component A.
Problem is when navigating from Component B to component A heading text is not read by screen reader.
Please help me to resolve this problem as I'm not finding any solution.
Below is the app link,
https://stackblitz.com/edit/react-ts-ckrut8?file=a.tsx
Simply cleaning up that code should be enough:
<h1 id="h1" tabindex="-1">Component 1</h1>
followed by
h1.focus()
There is a lot wrong in the posted code, which might cause the issues with the screen reader.
Most importantly it’s changing the H1’s role. Most screen reader users rely on finding headlines for orientation and navigation. There are shortcuts that help jump directly to the H1, for example.
An alert is not needed since focus is being moved to the headline. It will get announced on focus.
A <fieldset> is for forms and would need to have an accessible name. It’s simply invalid here.
How to React that?
To focus an element you’ll need to access the rendered DOM. Therefore you use the ref property along with useRef()
function MyComponent() {
const h1Ref = useRef(null);
useEffect(() => {
h1Ref.current.focus();
}, []);
return <h1 ref={h1Ref} tabIndex={-1} />;
}

Make child element of Link not route

I'm coding an application where people can make posts, and comment on them.
All of the posts are displayed on one page.
If a post is clicked the user gets routed to that post's page, which contains the full post, more details, and all of that post's comments.
Currently, I have the post div wrapped in a react-router Link. That works swell, except that when I click a button inside that div, I still get routed.
I want everywhere in the div to be "clickable", except actions like other Links or buttons.
<Link to={`/${_id}`}>
<div>
<button>I don't want this button to route</button>
</div>
</Link>
I'm not sure if there is a way to do this, but I can't find anything on it. I found one guy on another forum asking the same thing, but it was old and never got answered. Maybe I'm missing it, but I can't find it in the react-router docs. Maybe react-router is not even capable of this, idk?
Something like a quickfix but I don't know if its the best way to address this. I am looking first at the useRef but no avail.
Using something like e.preventDefault on the onClicks will probably save a lot of headache
<Link to="/">
<h1>Home</h1>
<button onClick={(e) => e.preventDefault()}>HAIYAAA</button>
</Link>
On hindsight this seems to be a Event Bubbling Issue right there.
See a fiddle here: https://codesandbox.io/s/react-router-forked-5rj2b?file=/index.js
EDIT:
Probably a much more dynamic way is to add a condition at the Link's OnClick and exclude the nested A (don't nest it otherwise React will nag you about it) and Button.
Basically we are dealing with a event bubbling here so might just use it to fine grain the behavior that we want. clicking anywhere inside the div will result to being routed to a page, while clicking any A or Button will not
<Link
to="/"
onClick={(e) => {
if (e.target !== e.currentTarget) {
if (["A", "BUTTON"].includes(e.target.nodeName)) {
e.preventDefault();
}
}
}}
>
<div>
Home
<br />
<button}>
HAIYAAA Don't Route me
</button>
<br />
<a href="#">
This is a link that is nested (Its not good to nest a!)
</a>
</div>
</Link>
Fiddle here: https://codesandbox.io/s/react-router-forked-4m4ww?file=/index.js
PS : ahh I spent time to learn something. Thanks for making my afternoon not a sleepy one
We need to stop the propagation of onClick event of the child to its parent.
<Link to="/">
<h1>Home</h1>
<button onClick={(e) => {
myNeededBehaviour();
e.stopPropagation();
}}>
HAIYAAA
</button>
</Link>
so, the stopPropagation will stop the event from propagating to its parent, and it will still calls myNeededBehaviour(); if you want, but the parent wont get the child's event. so it wont route, as it is not getting triggered.

ReactDOM.render does not re-render the 2nd element on the list

im having problem with ReactJS, i
on index.js i have:
ReactDOM.render([<App />, <Footer />], document.getElementById('root'));
the problem is that Footer needs to add an 80px padding from the bottom only on certain pages
so on the render method i do
<div>
{isMobile && window.location.pathname.startsWith('/summary') &&
<div style={{height: 80}}></div> }
</div>
but it doesn't re-render when window.location.pathname changes,
i move around the web app and it doesn't change only when i hit F5 it renders correctly on that page.
i tried using events on window but they're aren't invoked as well...
window.addEventListener('locationchange', function(){
console.log('xxxxxxx location changed!');
})
window.addEventListener('hashchange', function(e){console.log('xxxxxx hash changed')});
window.addEventListener('popstate', function(e){console.log('xxxxxxx url changed')});
how i can make it re-render? or make Footer work as React component that can render ?
This is a common problem!
Out of the box, React is configured to operate on a single page (see Single Page Applications), which basically means it deletes what's shown on screen and renders new information when an update is required.
Naturally, simulating the routing behavior that's observable for non Single Page Apps is a little more difficult - check out React Router, which is a library created to tackle this exact issue.

React - Why doesn't addEventListener work?

I am trying to create a website by using GatsbyJS, and I got stuck whenever I need to set a onClick event to toggle a class in one of my components. As a beginner with react and gatsby, I'm having a hard time to do it.
So essentially I want to make the following JS code in React/GatsbyJS:
const hamburger = document.querySelector('.burger_menur');
hamburger.addEventListener('click', function(){
this.classList.toggle('open');
});
The following code is my current code in Gatsby component. Have to say, I am using GSAP to make an animation.
This is my code:
import React from 'react';
import { Tween, Timeline } from 'react-gsap';
import '../styles/burger.scss'
const Burger = () => (
<Timeline
target={
<div className='burger'>
<div className='burger_menu'>
<div className='bar half start'></div>
<div className='bar'></div>
<div className='bar half end'></div>
</div>
</div>
}
>
<Tween from={{ opacity: '0', marginRight: '0rem' }} to={{ opacity: '1', marginRight: '5rem' }} ease="Back.easeOut" delay={2}/>
</Timeline>
);
export default Burger
Hopefully someone can help me out with this.
If you're going to go with React, don't manipulate the DOM directly.
More specifically, don't try to act directly on any part of the DOM generated by React.
Here, you're using plain DOM manipulation to attach your event to elements generated by React (also, there's a typo in your class name):
const hamburger = document.querySelector('.burger_menur');
hamburger.addEventListener('click', function(){
this.classList.toggle('open');
});
The thing is, while it may sometimes work, React will regenerate new elements for your menu when it deems it necessary, and your events listeners will be lost.
You have to do it "the React way":
...
<div className='burger'>
<div className={`burger_menu ${this.state.isOpen? ' open' : ''}`} onClick={() => this.setState({ isOpen: !isOpen })}>
<div className='bar half start'></div>
<div className='bar'></div>
<div className='bar half end'></div>
</div>
</div>
...
Don't forget to initialize your state with { isOpen: false }
Clicking the div will toggle this.state.isOpen, which is used to decide whether the class-name will be 'burger_menu' or 'burger_menu open'.
Note: There are more elegant ways to work with classlists when they get longer, but your component being simple and for the sake of clarity, a string template will more than do.
If any of this sounds confusing, please read through the official tutorial Intro To React, it's very well explained and covers everything needed here.
If you're already comfortable with this and want to know more about handling events in React, the docs has you covered once again: Handling Events

React: Invariant Violation (without table)

I have looked some answer in stackoveflow. But most of them have something todo with <table> and <tbody>. But my problem is nothing to do with that.
I render this <GISMapDropdownMenu> component using ScriptjsLoader of react-google-maps library.
initialCustomSetup: function() {
let GISMapDropdownMenu = this.refs.cornermenu;
if (googleMapInstance.props.map.controls[google.maps.ControlPosition.TOP_LEFT].j.length === 0) {// push only once
googleMapInstance.props.map.controls[google.maps.ControlPosition.TOP_LEFT].push(GISMapDropdownMenu);
GISMapDropdownMenu.style.zIndex = 1;
GISMapDropdownMenu.style.display = 'inline-block';
}
},
render: function() {
return(
<ScriptjsLoader
**** some setup ****
googleMapElement={
<GoogleMap
ref={googleMap => {
if (googleMap) {
googleMapInstance = googleMap;
layerType = self.props.layerType;
self.initialCustomSetup();
}
return;
}} >
<GISMapDropdownMenu
ref="cornermenu"
availableDesa={self.props.availableDesa}
availableDesaColor={self.props.availableDesaColor} />
{self.props.children}
</GoogleMap>
}
/>);
Here is the implementation of GISMapDropdownMenu.
<div className="gmnoprint GISMap-dropdownmenu" style={{display: 'none'}}>
<div>
<div ref="icon" className="GISMap-dropdownmenu--icon" onClick={this.handleIconClick}>
<img src={BurgerIcon} draggable="false" />
</div>
<div ref="content" className="GISMap-dropdownmenu--content" style={{display: 'none'}}>
<div className="GISMap-dropdownmenu--content_header">
<div className="GISMap-dropdownmenu--content_header__title">List of Desa ({number_of_desa})</div>
<div className="GISMap-dropdownmenu--content_header__cross" onClick={this.handleCrossCLick}>
<img src={CrossIcon} draggable="false" />
</div>
</div>
<div className='GISMap-dropdownmenu--content_list'>
{array_div_element_inrange_assigned_desa}
{array_div_element_inrange_desa}
{array_div_element_assigned_desa}
</div>
</div>
</div>
</div>
{array_div_element_something} is array of this.
<div key={"desa_name-"+desa.desa_name} className={"GISMap-dropdownmenu--content_list__"+desa_color.status}>Desa {desa.desa_name}</div>;
I got this error when use <GISMapDropdownMenu /> component.
Uncaught Error: Invariant Violation: processUpdates(): Unable to find child 97 of element. This probably means the DOM was unexpectedly mutated (e.g., by the browser),
I realised something:
I move the DOM of <GISMapDropdownMenu /> component after mounted. Because I need it to be in the top left of google map.
Any suggestion?
Potential problems: First off, these are guesses as I don't do React all the time, but having said that, here are some possible causes of this:
1) Unmounting components:
This probably means that setState is being called in a callback that was firing after the component that initially started the request has already been unmounted from the dom.
More details on this type of error
2) Having incomplete HTML tags in your markup
For example, adding a <p> tag without the closing </p>. The browser likes all html tags to be complete, so if it doesn't see an end tag for something, it'll add it. Try getting the HTML of your resulting component and comparing it to what you expect. Also remove the child components bit by bit (e.g. remove ) to see when it starts to work so you know what causes this problem. Your html from what I can see doesn't cause this.
3) Build your child components before rendering
Maybe you need to do as this similar answer does
4) Changing the DOM using something other than React
Is your page using jquery or something to change this component in anyway? ie bind events or add/remove anything? If so, this can be causing that as well. Try disabling this and see if it solves the problem
If none of the above help, I'd suggest adding a JSFiddle so people can see what the problem is for sure.

Resources