Mimic React custom component - reactjs

I have a custom Reactjs component to display Pagination with next/previous buttons at the bottom of a grid. Now, the business needs to display the same component on top of the grid as well. How to display the previous /next button events based on the input provided in prev/next buttons at the bottom of the grid?
I tried using javascript innerHTML to mimic the behaviour. It works only with the display. It does not attach the event listener of the buttons. I tried even with
document.querySelector.addEventListener('click', ()=>{console.log('test')})
It does not work. Is there a better way to do with react.

I am going to just add some more content to Shmili Breuer answer.
If i understood you correctly you have 2 navigations, one at the top one at the bottom. The way you connect them would be through a state of you component, or a parent component if you are using functional component to render pagination stuff. So if you change the state it will reflect on both of your navigations. Also you can use only one function here, by passing a parameter, im gonna copy a code from before mentioned answer.
// first create a function
nextFunction = (condition) => {
if(condition){
this.setState(prevState=>({
page: prevState.page-1
}))
} else {
this.setState(prevState=>({
page: prevState.page+1
}))
}
}
// then use it in your button
<button onClick={() => this.nextFunction(some condition)}>Next</button>

Just put that component on top and bottom
<Grid>
<Pagination />
{...someOtherComponents}
<Pagination />
</Grid>
it's ok in react. Optimization that you want to do is overhead.

In react you would add an onClick attribute to an element you want to handle a click on.
Something like this
// first create a function
nextFunction = () => {
do next functionality....
}
// then use it in your button
<button onClick={() => this.nextFunction()}>Next</button>
This way you can have both top and bottom pagination call the same function.
Hope this helps

Related

Modal start and exit animation logic inside a single React component

I have been trying to solve this problem for a very long time. I will be very glad for your help.
I have 3 functional components.
export const HomePage = () => {
const [menu,setMenu]=useState(false)
return (
<>
<Header menuState={()=>setMenu(!menu)} />
{menu&&<Menu/>}
</>
)
}
function Header(props){
return(
<div className='Header'>
<div className='button' onClick={()=>props.menuState()}/>
</div>
)
}
function Menu(props){
function animateExit() {
console.log("I'm trying to call this function from the Header component")
}
useEffect(() => {
function animateStart() {
console.log('Animation works! :)')
}
return()=>{console.log("In this case, the animation will not have time to appear, as the component will be instantly removed")}
},[]);
return(
<div className='Menu'/>
)
}
By clicking the button in the Header component, I am adding a Menu component to the home page. So I open the menu.
For smooth opening, I use an animation function, for example, I'll call it AnimateStart. It's in the "Menu" component in UseEffect .
To exit the menu, press the same button again.
I really want to put AnimateExit in the menu component. So all the logic of a component is inside that component.
For this you need either:
How to call this function from header component
Catch the removal of the component through the return of useEffect, but the function in the return must work until the removal. I don't know if this is possible.
At the moment, I'm writing exit animation logic in the Header component. It is not comfortable. I want to put all menu animation in Menu .
I hope you understand what I mean.
I would be glad for any advice on how to make a self-sufficient component, and not scatter its code into different blocks.
Thank you!
From what I was able to understand, you are currently facing problems with making the exit animation work because the Menu disappears quickly after clicking on the button in the Header component.
That is because your code mentions it clearly that show the Menu component only when menu variable is set to true. Which means your exit animation will not have time to be processed. The way you could handle this is by using CSS classes that have animation effect on them and you can switch between these classes based on the boolean value in your menu variable.
Refer to this example: CSS based animations
Also: Visibility with animation
I'd appreciate it if you could accept the answer if it helps your case!

React change class of component without using state

How can I change the className or style of a div without using state or any third party libraries? Lets say I click on a button, and I need to change the background color of a div how can I do that?
<Affix onChange={() => change css or class} offsetTop={60}>
<div>...</div> // Change css of this div
</Affix>
You can change any attribute or property of a Component (Element) in React by using basic javascript functions.
onClick={(e) => {
e.currentTarget.setAttribute("src", newUrl);
}
Will change an image the moment you click on it, without using Ref or State.
event.currentTarget will give you the reference to the component that fired that particular React.MouseEventHandler event, and with the Element's reference, you can manipulate it at will.
This is particularly useful when you need to change an attribute in a component in a map loop without needing to keep track of it.
Edit:
A friend of mine just gave me a better one for classes in specific:
e.currentTarget.classList.add('my_custom_klass')
You can either do it manually using state:
const [myClass, setMyClass] = useState('bgColor-white');
return (
<Affix onChange={() => setMyClass('bgColor-black')} offsetTop={60}>
<div className={myClass}>...</div> // Change css of this div
</Affix>
)
Or you can use a library that handles dynamic styling. I use and recommend styled-components

React global click track handler

I am new to react and working on a legacy codebase. Am wondering if we can write a global button click handler for click tracking.
The jQuery equivalent of this would be something like,
utilities.js :
var subscribeForClickTracking = function() {
$( "button" ).click((event) => { console.log($(event.target).html()) })
$( "p" ).click((event) => { console.log($(event.target).html()) })
}
In all the html files, will add reference to utiliies.js and this snippet of code.
$(document).ready(function () {
subscribeForClickTracking();
});
I have surfed about this and reached similar so questions, like
Higher Order React Component for Click Tracking
and https://www.freecodecamp.org/news/how-to-track-user-interactions-in-your-react-app-b82f0bc4c7ff/
But these solutions involve modifying the button's implementation, which would lead to huge change. (For a html form with 50+ buttons).
Is there an alternate approach to achieve something similar to the above jQuery approach.
Thanks in advance.
No, you can not do that. The reason is that React prevents you from doing global things to avoid side effects.
I think the proper React way would be to create your own Button component.
First create a new component :
export default Button = (props) => <button ...props />
Then, you can import and use Button instead of button in any component.
Then in your Button component, you can override your onClick method like this :
<button
...props
onClick={() => {
// doWhatYouWantHere;
props.onClick()
/>
However, as React is JavaScript, you can still use vanilla JavaScript to attach an event to every button

reusing stateful react components

I'm new to React and wanted some advice.
The problem is essentially thew following
I have a number of component buttons that open a modal, within this modal we have further buttons to offer a selection.
Home Screen Buttons (components)
<Button value="First"></button>
<Button value="Second"></button>
<Button value="Third"></button>.....
Modal.
<button value="Donald"></button>
<button value="Thomas"></button>
<button value="Evie"></button>.....
So the home screen buttons for example would have the following function, that it would pass down to the modal buttons onClick attribute.
selectPerson(e) {
setState({ selection : e.target.value})
}
So by selecting "First", we choose a person, close the modal, tie the selected person with Buttons state, and then repeat for second and so on.
Essentially these Buttons to open the modal have the same core functions (state and props). i.e I could have a template component an reuse it, but I would like each component to have independent state and props.
So I can achieve what I need but I've written each home screen button as an independent component, that is I've written a lot of the same code. If I attempt to reuse the SAME component, the are treated as the same component, and selecting a person changes all buttons state.
Is there anyway to avoid rewriting the same code for each (I have twenty). I've only just started (obviously) and am not too familiar with some of the more advanced concepts. If anyone has any suggestions or further questions, it would be great. I haven't provided code as the code works, its just extremely bulky
Yeah sure, define the button components and hand down certain elements inside its props.
You can then setState to be these handed down prop elements etc etc.
So define a button component with its various states defined by the props you hand it down. Then you have a mutable template Button component.
When you render these you just define its props.
<Button prop = "First" prop2 = "EXAMPLE"..../>
<Button prop = "Second" prop2 = "EXAMPLE2"..../>
<Button prop = "Third" prop2 = "EXAMPLE3"..../>
then inside the Button component use something like
this.state { property1 : this.props.prop, property2 : this.props.prop2 ...}
Hope this helps! I've recently been doing something similar

How do I call an event handler or method in a child component from a parent?

I'm trying to implement something similar to the Floating Action Button (FAB) in the Material-UI docs:
https://material-ui.com/demos/buttons/#floating-action-buttons
They have something like:
<SwipeableViews>
<TabContainer dir={theme.direction}>Item One</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab>{fab.icon}</Fab>
</Zoom>
));
}
I have something like:
<SwipeableViews>
<TabContainer dir={theme.direction}>
<ListOfThingsComponent />
</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab onClick={ListOfThingsComponent.Add???}>
Add Item to List Component
</Fab>
</Zoom>
));
}
My ListOfThingsComponent originally had an Add button and it worked great. But I wanted to follow the FAB approach for it like they had in the docs. In order to do this, the Add button would then reside outside of the child component. So how do I get a button from the parent to call the Add method of the child component?
I'm not sure how to actually implement the Add Item to List click event handler given that my list component is inside the tab, while the FAB is outside the whole tab structure.
As far as I know I can either:
find a way to connect parent/child to pass the event handler through the levels (e.g. How to pass an event handler to a child component in React)
find a way to better compose components/hierarchy to put the responsibility at the right level (e.g. remove the component and put it in the same file with this in scope using function components?)
I've seen people use ref but that just feels hacky. I'd like to know how it should be done in React. It would be nice if the example went just a bit further and showed where the event handling should reside for the FABs.
thanks in advance, as always, I'll post what I end up doing
It depends on what you expect the clicks to do. Will they only change the state of the given item or will they perform changes outside of that hierarchy? Will a fab be present in every single Tab or you're not sure?
I would think in most cases you're better off doing what you were doing before. Write a CustomComponent for each Tab and have it handle the FAB by itself. The only case in which this could be a bad approach is if you know beforehand that the FAB's callback will make changes up and out of the CustomComponent hierarchy, because in that case you may end up with a callback mess in the long run (still, nothing that global state management couldn't fix).
Edit after your edit: Having a button call a function that is inside a child component is arguably impossible to do in React (without resorting to Refs or other mechanisms that avoid React entirely) because of its one-way data flow. That function has to be somewhere in common, in this case in the component that mounts the button and the ListOfThings component. The button would call that method which would change the state in the "Parent" component, and the new state gets passed to the ListOfThings component via props:
export default class Parent extends Component {
state = {
list: []
};
clickHandler = () => {
// Update state however you need
this.setState({
list: [...this.state.list, 'newItem']
});
}
render() {
return (
<div>
<SwipeableViews>
<TabContainer dir={theme.direction}>
<ListOfThingsComponent list={this.state.list /* Passing the state as prop */}/>
</TabContainer>
<TabContainer dir={theme.direction}>Item Two</TabContainer>
<TabContainer dir={theme.direction}>Item Three</TabContainer>
</SwipeableViews>
{
fabs.map((fab, index) => (
<Zoom>
<Fab onClick={this.clickHandler /* Passing the click callback */}>
Add Item to List Component
</Fab>
</Zoom>
))
}
</div>
)
}
}
If you truly need your hierarchy to stay like that, you have to use this method or some form of global state management that the ListOfThingsComponent can read from.

Resources