I am trying to fetch the data to show the content as the frontend side. In this image
you can see I have mentioned the button with the div attributes i.e. in blue color.I tried the below code but I don't know how to create/handle the button and div.
import React from "react";
import {Col } from "react-bootstrap";
import "./style.scss"
class Example extends React.Component{
constructor(props){
super(props);
this.state = {
opencollapse: true,
}
}
toggle = () => this.setState((currentState) => ({opencollapse: !currentState.opencollapse}));
renderApps = () => {
const result = this.props.userdata.appliers.map((item, i) => {
return(
<div key={i}>
<div>
<div className="d-flex">
<Col>
<button onClick={this.toggle}>{this.state.opencollapse ? 'Click to close' : 'See Letter'}</button>
</Col>
<Col>
helloIcon
</Col>
</div>
{this.state.opencollapse && <div>{this.props.userdata.appliers[i].letter}</div>}
</div>
</div>
)
});
return result;
}
render(){
return (
<div>
{this.renderApps()}
</div>
);
}
}
export default Example;
I don't know where I did wrong.
In the image as you can see I tried to click on the number three button to open the third div but number 1 and number 2 button is also getting opened. I want to open those div which is opened by me, others let be closed. If I will click on button number one then div number one should be open and the rest should be closed vice versa.
It is because you have the same state variable for all buttons.
You can create another component.
Then each mapped component will have its own state
Child Component:
import React from "react";
import {Col } from "react-bootstrap";
import "./style.scss"
class ChildExample extends React.Component{
constructor(props){
super(props);
this.state = {
opencollapse: true,
}
}
toggle = () => this.setState((currentState) => ({opencollapse: !currentState.opencollapse}));
render(){
return (
<div>
<div>
<div className="d-flex">
<Col>
<button onClick={this.toggle}>{this.state.opencollapse ? 'Click to close' : 'See Letter'}</button>
</Col>
<Col>
helloIcon
</Col>
</div>
{this.state.opencollapse && <div>{this.props.text}</div>}
</div>
</div>
);
}
}
export default ChildExample;
renderApps function in Example component:
renderApps = () => {
const result = this.props.userdata.appliers.map((item, i) => {
return(
<ChildExample text={this.props.userdata.appliers[i].letter}
)
});
return result;
}
A good solution would be to create a seperate component for your button and the content its hiding. This way we can give each component their own state.
A simplified example can be found below:
class ToggleElement extends React.Component {
constructor(props){
super(props);
this.state = {
opencollapse: true,
};
}
toggle = () => {
this.setState((currentState) => (
{opencollapse: !currentState.opencollapse}
));
}
render() {
return (
<div>
<button onClick={this.toggle}>{this.state.opencollapse ? 'Click to close' : 'See Letter'}</button>
{this.state.opencollapse && <div>{this.props.item.letter}</div>}
</div>
)
}
}
class Example extends React.Component {
constructor(props){
super(props);
}
renderApps() {
return this.props.data.map((item, i) => (
<ToggleElement item={item} />
));
}
render() {
return (
<div>
{this.renderApps()}
</div>
);
}
}
// Render it
ReactDOM.render(
<Example data={[
{letter: 'A'},
{letter: 'B'},
{letter: 'C'},
]} />,
document.body
);
<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>
You can try making the state as array of states instead of one.
For example:
The state on constructor
constructor(props){
super(props);
let initOpenCollapse = [];
const n = 5; // This is set based on how many buttons you want to create
for (let i = 0; i < n; i++) initOpenCollapse.push(true);
this.state = {
opencollapse: initOpenCollapse,
}
}
The toggle function
toggle = (nthButton) => {
let resultState = [];
for (let i = 0; i < this.state.opencollapse.length; i++) {
if (i === nthButton)
resultState.push(!this.state.opencollapse[i]);
else
resultState.push(this.state.opencollapse[i]);
}
this.setState((currentState) => ({opencollapse: resultState}));
};
And in the render():
<button onClick={() => this.toggle(i)}>{this.state.opencollapse[i] ? 'Click to close' : 'See Letter'}</button>
...
...
{this.state.opencollapse[i] && <div>{this.props.userdata.appliers[i].letter}</div>}