reactJS adding an event listener to a navbar tile - reactjs

I am running the current version of reactJS with hooks. I have three code modules in my app: header.js which creates a navbar and exports it to app.js which adds some other objects and exports all of this to index.js.
I am trying to add an event listener to the individual tiles in the navbar so that I can redirect to the appropriate page.
code
var listenerElement = document.getElementById("Tile1");
if (listenerElement !== null) {
listenerElement.addEventListener("click", navbarClicked) ;
console.log(listenerElement);
} else {
console.log("Element with ID=Tile1 not found");
}
<div id="Tile1" className="linkcontainer">Home</div>
/code
However, I cannot find an appropriate place to add the event-listener and the element with ID "Tile1" is never found - perhaps because it hasn't been rendered as yet?
The element in question is only rendered by index.js but I can't add a function after the reactDOM.render block in index.js - I get an error "not a react function"
Any suggestions would be much appreciated :-)

For react, you should use "refs" to link to a specific aspect of the navabar.
But as you are just trying to have something affect the navbar, you should use the "onClick" property for the div or iconButton or similar.
for example in a function component:
function handleClick() {
console.log("clicked");}
<nav> <iconButton onClick={handleClick} > button </iconButton> </nav>
https://reactjs.org/docs/handling-events.html

In react, you don't work with the DOM directly. React makes a copy of the DOM called virtual DOM and then compares them to update the DOM. You should add your event listener using props.
So instead of:
document.getElementById("Tile1").addEventListener("click", navbarClicked);
you should do <div onClick={navbarClicked} id="Tile1" className="linkcontainer">Home</div>

Related

What happens when React rerenders?

I have the following code and you can view it on codeSandbox:
import "./styles.css";
import lottie from "lottie-web";
import { useEffect, useRef } from "react";
import logo from "pic";
export default function App() {
const el = useRef(null);
useEffect(() => {
if (el != null) {
lottie.loadAnimation({
container: el,
renderer: "svg",
loop: true,
autoplay: true,
animationData: logo
});
}
}, []);
return (
<div className="App">
<div ref={el}></div>
</div>
);
}
Lottie is just some library to render animation. The problem I have with it is that while I am in the developing phase, if I make some modification to the second div tag, then React rerenders without destroying the previous animation and in the meanwhile create a new animation below the original one. I am aware that one has to add some effect clearing logic in useEffect but I just do not see why.
I am new to React and only have a very basic understanding of how React works in the background, here is what I think: basically when I change the second div tag, the diff algorithm notices that it has been altered, so it goes ahead and tries to modify the dom associated with it. In my opinion it can 1). either update the current dom 2). delete it and append a new dom. In the first situation, shouldn't it leave the first animation unchanged without adding a new animation? In the second situation, if it gets rid off the current dom, why would the original animation be kept?
React can do both scenarios you mentioned: update existing and destroy & re-create. And React uses its own algorithm to decide when to do which.
You can force React to use destroy & re-create strategy using a special props called key.
Here is an example: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key
Quoted from the link above:
When a key changes, React will create a new component instance rather than update the current one
I couldn't run the example you provided via code sandbox and just by reading your code, I can see that your App component has no props and no state. Thus, there is no way for you to update it.
Your code said: when componentDidMount use lottie to do some animation inside the second div. So, chances are the animation issue you're having is probably coming from lottie not React.

Connected React Router - Don't update the view

I kinda need an advice here ... I'm learning how to build a full app based on react.
Here is the test app : https://codesandbox.io/s/cranky-platform-46sjl
Using React , Redux, Saga and typescript.
Everything work so far except the routing :
-Custon event are fired : onClick={() => redirectRequest('/')}
-When I manually try to access an url : /starwars for example : that work
-The router event is fired too in redux devtool : https://snipboard.io/uWaokq.jpg
-The Url change and the {location} in props + state is updated
-The view is not updating --> don't show the other components
I checked a lot of github issues / other stack questions but nothing seem to make it work so far.
Maybe you guy will have an idea of what I am missing here.
Thanks for your time !
Use NavLink as imported from react-router-dom
import { NavLink } from 'react-router-dom';
Later use it as follows in your render function
render () {
return (
...
<NavLink className="navlink" to="/">Home</NavLink>
...
)
}

Link in Infobox using react-google-maps causes page reload

I'm not able to put a react-router-dom Link inside of a react-google-maps InfoBox without causing a full page reload.
Here's the code for my InfoBox:
import InfoBox from 'react-google-maps/lib/components/addons/InfoBox'
import { Link } from "react-router-dom";
class MyInfoBox extends Component {
...
const options = {
enableEventPropagation:false,
position: new google.maps.LatLng(loc.latitude, loc.longitude)
};
render(){
return (
<InfoBox options={options}>
<Link to={`/location/${loc.id}`}>Go To Location</Link>
</InfoBox>
);
}
}
All Links in my app work correctly, except for this one.
When the "Go To Location" link is clicked, a full-page reload is caused. I've tried to diagnose by following this issue: https://github.com/tomchentw/react-google-maps/issues/258, but I really don't know enough about the react router v4 to find out if the context contains the router object. Changing the value of enableEventPropagation does not change the behavior.
If anyone can help me understand why the Link is causing a page reload, I would really appreciate it.
Thank you in advance!
Try removing onClick prop in <GoogleMap> component and add enableEventPropagation: true to <InfoBox> options.
For me the issue was that <GoogleMap> onClick event was used to remove <InfoBox> when user clicks outside it. But turns out it is called also inside <InfoBox> so basically it was removing <InfoBox> with the <Link> inside it, before handling <Link> click.

React + Material Design Lite - How to close navigation drawer when menu link is clicked?

so I am unsure of how to best go about closing the MDL drawer when a link is clicked inside the drawer. From similar questions I have gathered you simply need to remove the is-active class from both the div with a class of mdl-layout__obfuscator, and the div with a class of mdl-layout__drawer.
What is the best way to go about this in React? I am not using React-MDL by the way, I am using the CDN version if that matters or helps...
Sorry I am new to both React and MDL.
In most of the cases, we can use react state to handle the show/hide the component. But in this case, we cannot do as we dont have access to have state in react-mdl inbuilt component. So i would suggest to manipulate the react-mdl component.
What manipulate DOM? :O Really?
Yes. We are not doing DOM manipulation for our code, we are just manipulating react-mdl so I think this should not be a issue.
class Navbar extends Component {
hideToggle() {
var selectorId = document.querySelector('.mdl-layout');
selectorId.MaterialLayout.toggleDrawer();
}
render() {
return (
<Navigation>
<Link to={routes.XXX} onClick={() => this.hideToggle()}> XXX</Link>
</Navigation>
);
}
This should solve your issue.
Ref: Github source
Thank you.

How to behaviour test a Component which uses React Bootstrap with Jest

In pseudo code:
MyComponent: React.createClass
doThis: () ->
//do something
render: () ->
<div>
<button className='something' onClick={clickHandler()}>click this button</button>
<ReactBootstrap.Pagination onSelect=(this.doThis) items=3 />
</div>
//tests
component = TestUtils.renderIntoDocument <MyComponent>
//test1
el = TestUtils.findRenderedDOMComponentWithClass component, 'something'
TestUtils.Simulate.click el
//test2
el = TestUtils.srcyRenderedDOMComponentsWithTag component, 'li'
TestUtils.Simulate.click el[0]
In test1 the click is fired. In test2 doThis() is not called
In both cases I definitely have a dom node and am firing the click on it. onSelect is the correct prop to use to pass to ReactBoostrap.Pagination. It works fine in the browser.
The Pagination class in Bootstrap uses onClick and seems to attach it to the li element it renders so I think I am targeting the correct element. (Edit: looking at Bootstrap-react's test for the Pagination component that targets the a tag which is rendered inside the li https://github.com/react-bootstrap/react-bootstrap/blob/master/test/PaginationSpec.js. However; I tried that too so I don't think that is my problem).
It seems to be to do with trying to target a dom node rendered by a child component. But I have no idea how to proceed. (Edit: or perhaps it is specific to react-bootstrap? Maybe I need to not mock some dependency...?)
The answer, for me, was to not mock 'classnames' - which is a dependency of react-bootstrap:
jest.dontMock 'classnames'
The answer was given by: http://racingtadpole.com/blog/test-react-with-jest/ so thanks to racingtadpole.

Resources