Convert String in to a function call in ReactJS - reactjs

In my case buttons are created dynamically and functions names are assigned to them dynamically. Function names are received from DB. I know it is possible in JS but in reactJS, I couldn't assign my method names to the relevant Button.
Below is my current code
{this.state.btnArray.map((btnProps, index) =>
<button
key={index}
onClick={() => this.onButtonClick(btnProps.method)}
style={btnStyle}
>
{btnProps.value}
</button>
)}
Here onButtonClick is the method for all buttons, I want it to change for each button.

Try changing your onClick function to call the btnProps.method prop directly
{this.state.btnArray.map((btnProps, index) =>
<button
key={index}
onClick={() => btnProps.method()}
style={btnStyle}
>
{btnProps.value}
</button>
)}

Related

Highlight clicked button with React/Tailwind

I want to change the appearence of an button after clicking it.
I have tried adding focus: / active:, but react is re-rendering the component on-click, so it doesn't work.
In Javascript I would add an event-handler to every button that would automatically change the appearence after being clicked, how am I able to recreate that in react/tailwind-css, since tailwind is not working with dynamic className changes?
Is there a good practice, or should I add if statements in order to make it work?
This is what I am trying to recreate.
HTML:
<button>MY BUTTON</button>
<button>MY BUTTON</button>
<button>MY BUTTON</button>
JS:
let button_list = document.querySelectorAll("button");
button_list.forEach(element=>{
element.addEventListener("click",function(){
button_list.forEach(remove_background=>{
remove_background.style.background="white";
});
this.style.background="black";
});
});
I would recommend a state variable to store the active button. Here's a simple example:
const ButtonList = () => {
const [activeButtonIndex, setActiveButtonIndex] = useState(0);
return (
<>
<button
className={activeButtonIndex === 0 ? "bg-white" : "bg-black"}
onClick={() => setActiveButtonIndex(0)}
>
My Button
</button>
<button
className={activeButtonIndex === 1 ? "bg-white" : "bg-black"}
onClick={() => setActiveButtonIndex(1)}
>
My Button
</button>
<button
className={activeButtonIndex === 2 ? "bg-white" : "bg-black"}
onClick={() => setActiveButtonIndex(2)}
>
My Button
</button>
</>
);
};

How to pass parameters from a button in REACTJS?

I want to show only the paragraphs related to the selected chapter. To do this I did STATE with the selected Chapter number (the chapters are in numbers)
When I view the paragraphs in the page load it works fine.
I also want to make a list of buttons that move to the other chapters. The problem is that when I press the above buttons it does not change the STATE and I did console.log and really saw that the parameter I pass is incorrect. Where am I wrong in the code?
{allChapters.map(allChapter =>
<button key={allChapter} onClick={(allChapter) => this.handleChange(allChapter)}>
{allChapter}
</button>
)}
handleChange = (chapNum) => {
this.setState(({ currentChapter }) => ({ currentChapter: chapNum }))
console.log('chapNum', chapNum);
};
console.log()
It is important to note: {allChapter} is mirror number (1,2,3, ...) and the problem is not in it.
With your current code, the only thing you do is to rename the default onClick event parameter to allChapter. Just do this instead:
{allChapters.map(allChapter =>
<button key={allChapter} onClick={() => this.handleChange(allChapter)}>
{allChapter}
</button>
)}
Btw, you should change the variable name allChapter to chapter ;)
<button key={allChapter} onClick={(allChapter) => this.handleChange(allChapter)}>
{allChapter}
</button>
By doing this, you rename the default onClick event parameter with
allChapter
Then you pass this renamed event to the handleChange. It's why, your console.log shows an event.
The correct way to pass your parameter is :
<button key={allChapter} onClick={() => this.handleChange(allChapter)}>
{allChapter}
</button>

React - Generating different Icons within a map function

I have a sidebar components whose list items are generated inside of a map function (movie genres fetched from an api). I would like to have a different icon next to each of the movie genres but have been unable to figure out a way to create a different for each run of the map function.
My thoughts are
1st: make an array of the icons I would like to display, in the order that I would like them to display in.
const icons = [
"AiOutlineHome ",
"FaUserNinja",
"GiSwordman",
"GiBabyFace",
"FaLaughBeam",
"GiPistolGun",
"GiPineTree",
"GiDramaMasks",
"GiFamilyHouse",
"GiElfEar",
"GiScrollUnfurled",
"GiScreaming",
"GiMusicalNotes",
"GiMagnifyingGlass",
"FaRegKissBeam",
"GiMaterialsScience",
"GiHalfDead",
"GiGreatWarTank",
"GiCowboyBoot",
];
Then in my map function generate a different icon for each list item
{movieGenres.map((genre) => {
return (
<li key={genre.id} className="nav-text">
<button
className="genre-btn"
onClick={() => genreSelectionHandler(genre.id)}
>
*<GENERATE ICON HERE />*
<span className="nav-item-title">{genre.name}</span>
</button>
</li>
);
})}
Is it possible to pragmatically create components like this? So that I can avoid creating each list item individually if I want different icon.
You can just take the index of your genre to get the icon. The index is the second argument to the callback of your map() function:
{movieGenres.map((genre, idx) => (
<li key={genre.id} className="nav-text">
<button
className="genre-btn"
onClick={() => genreSelectionHandler(genre.id)}
>
<Icon icon={icons[idx]} />
<span className="nav-item-title">{genre.name}</span>
</button>
</li>
))}
The Icon component would render the icon depending on what kind of icons you are using.
EDIT:
As you want to use react-icons you need to import the actual icon components rather than just using strings:
import {AiOutlineHome} from "react-icons/ai";
import {FaUserNinja} from "react-icons/fa";
// ....
const icons = [
AiOutlineHome,
FaUserNinja,
// ...
];
And render them:
{movieGenres.map((genre, idx) => {
// must be a capitalized name in order for react to treat it as a component
const Icon = icons[idx];
return (
<li key={genre.id} className="nav-text">
<button
className="genre-btn"
onClick={() => genreSelectionHandler(genre.id)}
>
<Icon />
<span className="nav-item-title">{genre.name}</span>
</button>
</li>
)
})}

ReactJS buttons change color on click

I have 3 buttons in reactjs created with Material UI Buttons.
<>
<Button variant="contained">Button 1</Button>
<Button variant="contained">Button 2</Button>
<Button variant="contained">Button3</Button>
</>
How can I make that when clicking on one, it changes it's color (let's say blue) and the other ones reset to Default?
Because React use JSX, you can put javascript in your html component.
We can imagine a single state that manage your buttons.
in your component you create a state containing integer
const [buttonSelected, setButtonselected] = useState(0);
I'm using the react hook syntax, but it also depend on you implementation.
buttonSelected is the current value of the state and setButtonselected is the function that change the state. When you call it, React will rerender your component and change the display .
You can now add a click function on your return
...
<Button variant="contained" onClick={() => setButtonSelected(1)}>Button 1</Button>
<Button variant="contained" onClick={() => setButtonSelected(2)} >Button 2</Button>
<Button variant="contained" onClick={() => setButtonSelected(3)}>Button3 </Button>
...
This will change the value of buttonSelected each time you click a button.
We now need to change the color , for that we will use use makeStyle, but there is other way to do so.
First, create a style element outside of your component.
const useStyles = makeStyles((theme: Theme) =>
createStyles({
selected: {
background: 'blue',
},
default:{
background: 'default',
}
}
),
);
Then call it in your component
const classes = useStyles();
And finally you can set the style that you want depending on the value
...
<Button className={(buttonSelected === 1) ? classes.selected : classes.default} variant.....
<Button className={(buttonSelected === 2) ? classes.selected : classes.default} variant.....
<Button className={(buttonSelected === 3) ? classes.selected : classes.default} variant.....
...
This is a ternary operator, it's the equivalent of
if(buttonSelected === 1){
return classes.selected
} else {
return classes.default
}
And it should work.
You can learn about it in the conditional rendering of react and in the the styling in react
Dont hesitate if you got any questions :)

Avoid list opening when clicking a custom Token with react-bootstrap-typeahead

I'm using the multiple token configuration and I want to create a custom token, so I just extend tokenContainer as the documentation says:
const TokenSkill = tokenContainer(props => {
return <div
onClick={(event) => {
event.stopPropagation();
props.onClickCustom(event);
}}
className="tokenSkill">{props.children}
<span onClick={() => props.onRemove()}
><i className="fa fa-times crossButton" /></span>
</div>
});
I want some data to display when a token is clicked. I've implemented my onClick version. But whenever I click it, the filter panel shows. It seems it is grabbing the same event when clicking in the filter box.
I've created this codeSandbox as example https://codesandbox.io/s/o9r23yklq9
If you search a token (try with "house") and add it on the list, when you click in the token it will display the filter list along with an alert. It should only show that list when clicking in an empty space on the filter list
There are two issues with your code:
You're not passing all the tokenContainer props to your custom token. Among those props is an onFocus handler that stops propagation of the click to the parent, ie: the input.
Because you're using a div as the containing element, you need to set a tabIndex for the token to retain focus.
The following should work:
const TokenSkill = tokenContainer(props => {
return (
<div
{...props}
onClick={(event) => {
event.stopPropagation();
props.onClickCustom(event);
}}
className="tokenSkill"
tabIndex={0}>
{props.children}
<span onClick={() => props.onRemove()}>
<i className="fa fa-times crossButton" />
</span>
</div>
);
});
Here's a working sandbox: https://codesandbox.io/s/74n5rvr75x

Resources