Bootstrap collapse with react js - reactjs

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

Related

Using the right pattern in react to add an id without passing it directly using props but through map?

I have this code on Codesandbox the goal is to be able to pass 5 Divs, on load using use Effect.
and a second option to add a div on click when if the user feels like it. the code is partially working, but it has a anti-patter issue which is putting the component in the state instead of changing the state using map to pass the changes..
please take a look I would like to hear your opinion on this, what I do understand is importing the Div element like this could affect performance, I want to avoid bad practice as much as possible.
import React, { useEffect, useState } from "react";
import Div from "./Div";
import "./styles.css";
import { v4 as uuidv4 } from "uuid";
export default function App() {
useEffect(() => {
// on start add 5 divs in to the local state Array on the frist load
});
const [div, setDiv] = useState([]);
const addDiv = () => {
// add an extra div on click if needed with id using the right pattern
setDiv([...div, <Div id={uuidv4()} />]);
};
return (
<div className="App">
{div}
<button onClick={addDiv} type="button">
Click Me!
</button>
</div>
);
}
//Dev dependencise
"uuidv4": "6.2.12"
Codesandbox
Putting JSX elements into state is a bad idea because they won't be reactive - you won't be able to (reliably) pass down state, state setters, and other useful things as props.
It's not so much a performance issue as a code maintainability issue - if you add additional functionality to your Div component and to your App you may find that your current approach won't work due to stale values that the JSX elements in state close over.
If you need the ability to delete a value, use the index of the div in the array and pass it down as needed. For a quick and dirty example:
function App() {
const [texts, setTexts] = React.useState([]);
const [text, setText] = React.useState('');
React.useEffect(() => {
setTexts(['a', 'b', 'c', 'd', 'e']);
}, []);
const addDiv = () => {
setTexts([...texts, text]);
setText('');
};
return (
<div className="App">
{
texts.map((text, i) => (
<div>
<span>{text}</span>
<button onClick={() => setTexts(texts.filter((_, j) => j !== i))}>delete</button>
</div>
))
}
<button onClick={addDiv} type="button">
Click Me!
</button>
<input value={text} onChange={e => setText(e.target.value)} />
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Just add id in the array and using map to render
{div.map(id => (
<Div key={id} id={id} />
))}
const addDiv = () => {
setDiv([...div, uuidv4()]);
};

How do I set focus on component html tag

I need to set focus on tag in my functional component when it loads. I cannot make it work properly. Please help! Below is my code;
Detail.js
import React,{useState,useEffect} from 'react';
const Detail=({course})=>{
const [myfocus]=useState(null);
useEffect(() => {
setState({
this.myfocus.focus(); //? how to set id myfocus to this.myfocus.focus()
});
return (
<div>
<h4 tabindex="0" id="myfocus">
{course.SUBJECT} {course.CATALOG_NBR}
</h4>
</div>
);
};
export default Detail;
We have autoFocus prop in React, so you can try <h4 autoFocus />.
But you can also solve this with the ref:
const h4 = useRef()
useEffec(() =>
h4.current.focus()
)[];
return( <h4 ref={h4} /> )
You are right, that tabIndex (use camel case in React) is probably required to make it work for the h4 element.

How to redirect to another page on button click in Reactjs

I want to create a basic web application using react. I have implemented creating buttons. I want to redirect to another page on button click. Below is my App.js code
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<p>
<buttontoolbar>
<button const path = '/Components'> Click Me </button>
</buttontoolbar>
</p>
</header>
</div>
);
}
export default App;
When i click on 'click me' button it should redirect to Components.js. Below is the code for Components.js
import React from "react"
function app(){
return(
<p>
Welcome to the world.
</p>
)
}
export default app
Long back i have done these king of things in ASP.NET. there i have used Response.redirect to redirect pages which is so simple. As I am new to React, i know nothing about this. Is there anything like that in React?
Basically React does not have "pages". The idea is more to "show" or "hide" components, this gives the user a page/view impression.
The easiest way to achieve routing in React is to use a declarative router library like react router especially for more complex apps.
Here is an example without react router to understand the basic concept:
const ViewOne = ({onClick}) => (
<div>
View 1 <br />
<button onClick={() => onClick("view2")}>Go to view 2</button>
</div>
);
const ViewTwo = ({onClick}) => (
<div>
View 2 <br />
<button onClick={() => onClick("view1")}>Go to view 1</button>
</div>
);
const App = () => {
const [currentView, setCurrentView] = React.useState("view1");
return (
<div>
{
currentView === "view1" ?
<ViewOne onClick={page => setCurrentView(page)} /> :
<ViewTwo onClick={page => setCurrentView(page)} />
}
</div>
);
};
const domContainer = document.querySelector('#my-app');
ReactDOM.render(<App />, domContainer);
<div id="my-app"></div>
<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>
Use react-router-dom package to define routing and then use one of below mentioned ways on onClick event of button.
this.props.history.push("componentpath").
browserHistory object (in react-router package).
Please refer this Link
try Link component of react-router-dom and pass to as a path to it wherever you want to redirect on onClick.
import { Link } from 'react-router-dom'
and Eg.
<Link to={'/Components'}>
<button > Click Me </button>
</Link>
const {Link, BrowserRouter} = window.ReactRouterDOM
function App(){
return (
<BrowserRouter>
<button><Link to='/abc' target='_blank'> Click Me </Link></button>
</BrowserRouter>
)
}
ReactDOM.render(<App/>, document.getElementById("root"))
<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>
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
<body><div id="root"></div></body>

Not Able to Toggle Class Using React Componnent

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.

React stripping out onclick

I have the following React component:
class PlayerRow extends Component {
activateKey(){
$(this).addClass('active')
}
render() {
return (
<div className="row-par">
<div className="details-cont">
</div>
<div className="key-cont">
<div onClick={this.activateKey} className="key"></div>
<div onClick={this.activateKey} className="key"></div>
<div onClick={this.activateKey} className="key"></div>
</div>
</div>
)
}
}
I am trying to perform the function activateKey on click of on of the nested divs but whenever I render out the app my onclick attribute is stripped out of all the divs. Why would this be?
React binds event listeners itself, so onClick does not directly result in onclick attribute in DOM. However, your code actually works (see snippet).
class PlayerRow extends React.Component {
activateKey() {
console.log('ddd')
}
render() {
return (
<div className="row-par">
<div className="details-cont">
</div>
<div className="key-cont">
<div onClick={this.activateKey} className="key">asd</div>
<div onClick={this.activateKey} className="key">qwe</div>
<div onClick={this.activateKey} className="key">zxc</div>
</div>
</div>
)
}
}
ReactDOM.render(
<PlayerRow/>,
document.getElementById('container')
);
<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">
<!-- This element's contents will be replaced with your component. -->
</div>
I suggest 2 things though, use .bind(this) for action handler or even better, use arrow function as it inherits scope by default.
From react docs:
handleClick = () => {
console.log('this is:', this);
}
see: https://facebook.github.io/react/docs/handling-events.html
Second thing - don't use jQuery. You're using React to manage DOM, and jQuery produces side-effects by default, so, it will interfere with how react works. React renders your view according to component's state or props automatically, with it's optimizations which are awesome, and jQuery doesn't edit neither props nor state, so you don't take advantage of any react's cool stuff.
For what you want to achieve, you could give your action handler a parameter which tells you which block has been clicked onClick={() => activateKey(1)}. In the handler save the active id on local state, and give your blocks the class conditionally depending on if their id matches the key id. That's my idea.
Using ES6 arrow function or .bind() in the render method adds unnecessary overhead to your components. You really should .bind(this) to your methods in the constructor like such:
import React, { Component } from "react";
export default class Demo extends Component {
constructor(props) {
super(props);
this.activateKey = this.activateKey.bind(this);
}
activateKey() {
console.log("ddd");
}
render() {
return (
<div className="row-par">
<div className="details-cont"></div>
<div className="key-cont">
<div onClick={this.activateKey} className="key">asd</div>
<div onClick={this.activateKey} className="key">qwe</div>
<div onClick={this.activateKey} className="key">zxc</div>
</div>
</div>
);
}
}
If you do this, the bind operation is only performed once per method during the class initialization phase. If you use ES6 arrow functions or .bind(this, etc..) inside of your render method, the binding will be executed from each element that has an onClick event, on every re-render.
The only time you should use .bind(this, etc..) or an ES6 arrow function inside of the render method is if you need to pass something other than a click event to a function.

Resources