Not Able to Toggle Class Using React Componnent - reactjs

Can you please take a look at this demo and let me know why I am not able to toggle .green class for #root using onClick in react js?
function toggler(e){
var x = document.getElementById("root");
x.classList.toggle('green');
}
const Button = ({ styleClass, onClick, text }) => {
return (
<button
type="button"
onClick={e => onClick(e)}
className={`btn ${styleClass}`}
>
{text}
</button>
);
};
ReactDOM.render(
<div>
<Button styleClass="btn-primary" text='Primary Button' onClick={toggler} />
</div>
, window.root);
#root{
height:300px;
width:300px;
background:khaki;
}
.green{
background:green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div id="root"></div>

You should not touch the DOM directly when you're writing React components. React can help you manage your class name with state.
Do something like this:
import React, { Component } from 'react';
export default class Button extends Component {
constructor(props) {
super(props);
this.state = {
buttonStyleClass: 'bar'
}
}
toggler = (e) => {
this.setState({
buttonStyleClass: 'foo'
})
}
render() {
return (
<div
className={this.state.buttonStyleClass}
onClick={this.toggler}
>
Click me
</div>
);
}
}

The problem here is that id-selectors have higher priority over class-selectors in css. Since you have defined the base color with #root, you can't toggle it with just .green.
Many solutions here, but one of them could be #root.green, adding !important or selecting your root otherwise.
That being said, you should not mutate the DOM directly when using React. It voids one of its biggest advantages. See mxdi9i7's answer for more info.

Related

How do I import react-modal into existing application?

I've been slowly trying to migrate some pieces of an existing, large php/jquery project to use ReactJS, especially using some reusable components. ReactJS has been working well for me, but today I tried to import a library using npm, which is completely new to me.
After running npm install react-modal I see that node_modules\react-modal (along with several other folders) were created. So far, so good.
However, I cannot seem to include that component into my project. If I try import ReactModal from 'react-modal'; at the top of my component's .js file, I get: Uncaught ReferenceError: require is not defined. I get errors thrown if I try to include the node_modules\react-modal\lib\components\Modal.js file directly, which I realize is probably the wrong approach but I'm grasping at straws here. I suspect I'm missing something basic, but I just can't seem to figure this one out. Does anyone have any ideas?
Edit: here is how I include React into my project currently:
<!-- Load React. -->
{if $env=="prod"}
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
{* tabs support *}
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-tabs#3/dist/react-tabs.production.min.js"></script>
<link href="https://unpkg.com/react-tabs#3/style/react-tabs.css" rel="stylesheet">
{else}
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
{* tabs support *}
<script src="https://unpkg.com/prop-types/prop-types.js"></script>
<script src="https://unpkg.com/react-tabs#3/dist/react-tabs.development.js"></script>
<link href="https://unpkg.com/react-tabs#3/style/react-tabs.css" rel="stylesheet">
{/if}
{* Babel support *}
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
This is the full component (contents of the matchSelector.js file):
import Modal from 'react-modal';
/**
* Select a match with hooks to return the proper match info to the instantiator
*/
class MatchSelector extends React.Component {
/**
* Class Constructor
*
* props expected:
* className - (optional) use if you want to style the picker button/icon differently. Note that
* if given, all standard classes will be overrided.
*
* type - (optional) can be "text", "icon", "both". Default is "both".
*
* text - (optional) if type is "text" or "both", the text to use on the button. Default is "Select Match"
*
*/
constructor(props) {
super(props); // let Dad know what's up
this.state = {showDialog:false}
this.handleClick = this.handleClick.bind(this);
this.handleClose = this.handleClose.bind(this);
}
handleClick(event) {
event.preventDefault();
this.setState({showDialog:true});
}
handleClose() {
this.setState({showDialog:false});
}
render() {
const defaultClassName = "ui-state-default ui-corner-all ui-button compressed";
let className = (odcmp.empty(this.props.className)?defaultClassName:this.props.className);
return (
<React.Fragment>
<button
className={className}
onClick={this.handleClick}>
{this.buttonContent()}
</button>
<MatchSearchDialog
show={this.state.showDialog} />
</React.Fragment>
);
}
buttonContent() {
var text = (odcmp.empty(this.props.text)?"Select Match":this.props.text);
if (odcmp.empty(this.props.type) || (this.props.type.toLowerCase()=="both")) {
return (
<span><span className="ui-icon ui-icon-search inline"></span>{text}</span>
);
} else if (this.props.type.toLowerCase()=="icon") {
return (
<span className="ui-icon ui-icon-search inline"></span>
);
} else {
return text;
}
}
}
class MatchSearchDialog extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactModal isOpen={false}><div>hi</div></ReactModal>
);
}
}
The doc of the npm package state that to import your modal, you need to write:
import Modal from 'react-modal';
It's not import ReactModal from 'react-modal'; as you tried (ReactModal => Modal).
With this eveything works fine for me as you can see on this repro on Stackblitz. Here is the code :
import React, { Component } from "react";
import { render } from "react-dom";
import Hello from "./Hello";
import Modal from 'react-modal';
import "./style.css";
Modal.setAppElement('#root');
const App = () => {
const [modalIsOpen,setIsOpen] = React.useState(false);
const openModal = () => {
setIsOpen(true);
}
const closeModal = () => {
setIsOpen(false);
}
return (
<div>
<p>Start editing to see some magic happen :)</p>
<button onClick={openModal}>Open Modal</button>
<Modal
isOpen={modalIsOpen}
contentLabel="Example Modal"
>
<div>Wow nice modal !</div>
<button onClick={closeModal}>close</button>
</Modal>
</div>
);
};
render(<App />, document.getElementById("root"));
In case anyone runs into this, I wanted to add my resolution.
I was trying to run a bare bones REACTJS project without webpack. react-modal depends on webpack (as does, I'm sure, many React components). As I'm trying to stay light and agile, I removed the react-modal module and "rolled my own" modal dialog.
FYI, the clue is the "require not defined" error in the console - indicating a non-browser (node.js) function was hit. It was expecting to compile (webpack) into a separate js file using the node.js terminology.

on click i want to generate alert in react js method

This is my code:
generateAlert = () => {
alert('hi');
}
return <Tile
click={(index)=>{this.generateAlert}}
title={tile.title}
value={tile.value}
key={tile.id}
/>
This is the error I'm getting:
Expected an assignment or function call and instead saw an expression no-unused-expressions
Search for the keywords to learn more about each error.
First, I do wonder if in your Component you have an array of Tile data, and you want to render a Tile for each entry of the array (I thought so because you added the key prop to Tile).
Anyways, I made an example similar to what you want to achieve, and it's working. Look at this:
const Tile = (props) => {
return (
<div className="Tile">
<h3>{props.title}</h3>
<div onClick={props.click}>
{props.value}
</div>
</div>
);
}
class App extends React.Component {
constructor(props) {
super(props);
}
generateAlert = () => {
alert("Hi");
}
render() {
return (
<Tile
click={this.generateAlert}
title={"This isa a Title"}
value={"This is the value"} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
#import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Now, I may help you in a deeper way if you would post the code of the Component that wants to render Tile; maybe, there are some error in that.
Hei!
If it's a function invocation inside your component's onClick function, you need to add () after this.generateAlert in your component
So it's gonna be like:
return <Tile
click={(index)=>{this.generateAlert()}}
title={tile.title}
value={tile.value}
key={tile.id}
/>
Otherwise, you can use your function as a onClick callback per se.
In that case you need to have it like this:
return <Tile
onClick={this.generateAlert}
title={tile.title}
value={tile.value}
key={tile.id}
/>
Cheers!
I will do in this way:
Q: why I export Tile to new component?
A: As each component should be as short as possible. There is a many advantages to doing in this way
like: "easy to find bugs (testing)".
import React, { Component } from "react";
import Tile from "./Tile";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.generateAlert = this.generateAlert.bind(this);
}
generateAlert = () => {
alert("Hi");
};
render() {
return (
<Tile
click={this.generateAlert}
title={"This isa a Title"}
value={"This is the value"}
/>
);
}
}
export default App;
and file Tile.js:
import React, { Component } from "react";
export default class Tile extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<button onClick={this.props.click}>click me</button>
<p>{this.props.title}</p>
<p>{this.props.value}</p>
</div>
);
}
}
This file Tile.js are ready for future addons but if you want to use only like it is now I would recommend to change into stateless component:
import React from "react";
const Tile = props => {
return (
<div>
<button onClick={props.click}>click me</button>
<p>{props.title}</p>
<p>{props.value}</p>
</div>
);
};
export default Tile;

How to change buttons inside react-table using if and else statement?

My reactJS web page has this react-table with 2 buttons inside, I want to change those button when a cell column status changes its value.
render() {
const columns = [
{
Header: "Actions",
accessor: "ID",
Cell: ({ value }) => (
<div style={buttonTablestyle}>
<Button
bsStyle="info"
onClick={() => {
if (window.confirm("You are approving this request after you press OK...")) {
this.updateFunctionYES(value);
}
}}
>
Approve
</Button>
<Button
bsStyle="warning"
onClick={() => {
if (window.confirm("You are rejecting this request after you press OK...")) {
this.updateFunctionNO(value);
}
}}
>
Reject
</Button>
</div>
)
}
];
}
Conditional Styling
The most basic way for conditional styling is to use state and style-objects, which will be explained below. Noteworthy alternatives for conditional styling with prettier syntax and better readability are classnames and styled components.
1) define the state
whenever you want to change a style depending on a value this value should be part of the state, since any change in the state triggers a re-render
2) define style outside the render function
when re-rendering you want to access the styles without re-defining them each time.
3) assign style depending on state
you then assign your needed style within a ternary operator, if statement or switch to use it within your html element.
Example
// define styles you want to use depending on state
const green = {
background: 'green'
}
const red = {
background: 'red'
}
class MyComponent extends React.Component {
state = {
toggle: false
}
handleClick() {
// change state on click
this.setState({
toggle: !this.state.toggle
});
}
render() {
// state change triggers re-render
// define style to be used depending on state
let myStyle = this.state.toggle ? green : red;
return <div>
<div style={myStyle}>MyApp</div>
<button onClick={this.handleClick.bind(this)}>click me</button>
</div>;
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app'></div>
Conditional Displaying
If you want to hide/show conditionally you can add display: none to one of the styles or you use the state to only return the jsx you want to display.
class MyComponent extends React.Component {
state = {
toggle: false
}
handleClick() {
// change state on click
this.setState({
toggle: !this.state.toggle
});
}
render() {
// state change triggers re-render
let element1 = <div>element1</div>;
let element2 = <div>element2</div>;
// define object to be used depending on state
let elementToUse = this.state.toggle ? element1 : element2;
return <div>
{elementToUse}
<button onClick={this.handleClick.bind(this)}>click me</button>
</div>;
}
}
ReactDOM.render(
<MyComponent />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='app'></div>

integrating js code inside react component

I have converted a component that displays chart bar, and it requires this js snippet to run, what is the correct way of integrating it inside my JSX code?
<script>
/** START JS Init "Peity" Bar (Sidebars/With Avatar & Stats) from sidebar-avatar-stats.html **/
$(".bar.peity-bar-primary-avatar-stats").peity("bar", {
fill: ["#2D99DC"],
width: 130,
})
</script>
I have seen this libraries on npm website, but they mostly deal with external scripts not internal
here is my component:
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<div>
"How can I render js code here?"
</div>
);
}
}
You can use refs and componentDidMount callback in order to initialize jquery plugins, like so
class App extends React.Component {
componentDidMount() {
$(this.barChart).peity("bar", {
fill: ["#2D99DC"], width: 130
});
}
render() {
return <div>
<div ref={ (node) => { this.barChart = node } }>
<span class="bar">5,3,9,6,5,9,7,3,5,2</span>
<span class="bar">5,3,2,-1,-3,-2,2,3,5,2</span>
<span class="bar">0,-3,-6,-4,-5,-4,-7,-3,-5,-2</span>
</div>
</div>;
}
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/peity/3.2.1/jquery.peity.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>
You should use componentDidMount lifecycle hook.
Add this to your component code:
componentDidMount() {
$(".bar.peity-bar-primary-avatar-stats").peity("bar", {
fill: ["#2D99DC"],
width: 130,
})
}

Bootstrap collapse with react js

Hi I'm trying to use bootstrap collapse inside a react view and it's not working. It's very simple but I don't understand what's going on.
return (<div>
<button className="btn" type="button" data-toggle="collapse" data-target="#collapseExample" aria-expanded="true" aria-controls="collapseExample">
ButtonClickthis!
</button>
<div className="collapse" id="collapseExample">
<div className="well">
...blablablacontent
</div>
</div>
</div>);
Bootstrap will not work out of the box for react components, since it parses the DOM on load and attaches event listeners etc. You can try something like react-bootstrap or manually triggering inside the componentDidMount lifecycle.
– David
Bootstrap 5 no longer requires jQuery which makes it easier to use with React. For example, here's the Bootstrap Collapse component using the React useState, useEffect hooks:
import { useState, useEffect } from React
import { Collapse } from bootstrap
function CollapseDemo() {
var [toggle, setToggle] = useState(false);
useEffect(() => {
var myCollapse = document.getElementById('collapseTarget')
var bsCollapse = new Collapse(myCollapse, {toggle: false})
toggle ? bsCollapse.show() : bsCollapse.hide()
})
return (
<div className="py-2">
<button className="btn btn-primary" onClick={() => setToggle(toggle => !toggle)}>
Toggle collapse
</button>
<div className="collapse" id="collapseTarget">
This is the collapsible content!
</div>
</div>
)
}
Demo
Figured I'd add an update here. With the updated version of React, not only do you not need vanilla code such as document.getElementById(), but you don't need refs either, or jQuery for that matter. You can simply import collapse like so:
import Collapse from 'react-bootstrap/Collapse'
The collapse transition can be accomplished very easily with this component, as shown in the docs. Here's the code pulled from the same:
const {useState} = React;
const Example = () => {
const [toggle, setToggle] = useState(false);
const toggleFunc = React.useCallback(() => setToggle(!toggle));
return (
<div>
<button onClick={toggleFunc}>Toggle Collapse</button>
<ReactBootstrap.Collapse in={toggle}>
<div>
Stuff to collapse
</div>
</ReactBootstrap.Collapse>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/react-bootstrap#next/dist/react-bootstrap.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div id="react"></div>
** Note: Obviously this code was modified to work with code snippets here on SO. If you're working in your local environment, use the code from the docs, which is even cleaner.
If you don't want to mess around with jQuery:
First, build a ref object for each of your collapsible elements; also build a function to toggle the .show CSS class to the corresponding element.
Then, use toggler function in a button onClick.
class Collapse extends React.Component {
constructor(props) {
super(props)
this.refs = {}
// build ref object with collapsible elements ids
this.setRef = (element) => {
this.refs[element.id] = element
}
// toggle "show" CSS class using plain JS
this.collapseRef = (id) => {
if (this.refs) this.refs[id].classList.toggle('show')
}
}
render() {
return (
<div>
<button
type="button"
onClick={() => this.collapseRef('content1')}
>
Collapse!
</button>
<div
className="collapse"
// Use the `ref` callback to store a reference to the collapsible DOM element
ref={this.setRef}
id="content1"
>
Collapsible content
</div>
</div>
)
}
}
I experienced this before. All you need to do is manually trigger events inside componentDidMount. You might also want to re-triggering the events in the callback of the setState.
Install the module with npm
npm install react-bootstrap bootstrap
And import in your component
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
This work for me

Resources