How can I have conditional buttons without repeating code. React - reactjs

I am trying to make it so the buttons are only visible in my create page. I have figured out how to do this although in such a way that code is repeated
if (mode != "view") {
return (
<>
<section
className={`col-md-${sectionInputArray.width} justify-content border-end mt-2 mb-2`}
>
<h4 className="border-bottom">{`${sectionInputArray.name}`} </h4>
<div className="col-12"></div>
{sectionInputArray.contents.map((input, i) => (
<NestedDynamicInputCreation
singleInput={input}
formData={formData}
setFormData={setFormData}
options={options}
mode={mode}
staticVars={staticVars}
SetStaticVars={SetStaticVars}
i={i}
idx={idx}
arrayLength={arrayLength}
sectionUID={sectionInputArray.UID}
/>
))}
{/* Button to add new field */}
<button
id ="TestButton1"
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
// console.log(`${sectionInputArray.name} section will be added`);
// console.log({ formDataTarget: formData[sectionInputArray.UID] });
// New Inbound Rule
// console.log([
// ...formData[sectionInputArray.UID],
// NestedListIDSingle(sectionInputArray),
// ]);
let addedFormData = {
...formData,
[`${sectionInputArray.UID}`]: [
...formData[sectionInputArray.UID],
NestedListIDSingle(sectionInputArray),
],
};
let randomVal = Math.random()
.toString(36)
// .replace(/[^a-z]+/g, "")
.substr(0, 11);
let withRandom = {
...addedFormData,
rand_value: randomVal,
};
// console.log({ addedFormData: addedFormData });
setFormData(withRandom);
}}
>
Add New {sectionInputArray.name}
</button>
{/* Button to remove section (or created form) */}
<button
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
console.log(
`${sectionInputArray.name}-${idx} section will be removed`
);
// formData[sectionInputArray.UID].splice(idx, 1);
let formDataTarget = formData[sectionInputArray.UID];
// console.log(formDataTarget);
let newFD = formData;
newFD[sectionInputArray.UID].splice(idx, 1);
let randomVal = Math.random()
.toString(36)
// .replace(/[^a-z]+/g, "")
.substr(0, 11);
let withRandom = {
...newFD,
rand_value: randomVal,
};
setFormData(withRandom);
}}
>
Remove {sectionInputArray.name}
</button>
</section>
</>
);
} else {
return (
<>
<section
className={`col-md-${sectionInputArray.width} justify-content border-end mt-2 mb-2`}
>
<h4 className="border-bottom">{`${sectionInputArray.name}`} </h4>
<div className="col-12"></div>
{sectionInputArray.contents.map((input, i) => (
<NestedDynamicInputCreation
singleInput={input}
formData={formData}
setFormData={setFormData}
options={options}
mode={mode}
staticVars={staticVars}
SetStaticVars={SetStaticVars}
i={i}
idx={idx}
arrayLength={arrayLength}
sectionUID={sectionInputArray.UID}
/>
))}
</section>
</>
)
As you can see above when it is not on the view page it will then not use the buttons as it is removed within the 'else' section.
How could i create an instance of this, when the button is conditional. I tried placing an if statement just before the button section however that did not work

Yes you can do it - place your conditional rendering (operator &&) after your <NestedDynamicInputCreation
return (
<>
<section
className={`col-md-${sectionInputArray.width} justify-content border-end mt-2 mb-2`}
>
<h4 className="border-bottom">{`${sectionInputArray.name}`} </h4>
<div className="col-12"></div>
{sectionInputArray.contents.map((input, i) => (
<NestedDynamicInputCreation
singleInput={input}
formData={formData}
setFormData={setFormData}
options={options}
mode={mode}
staticVars={staticVars}
SetStaticVars={SetStaticVars}
i={i}
idx={idx}
arrayLength={arrayLength}
sectionUID={sectionInputArray.UID}
/>
))}
{mode != 'view' && (
<>
<button
id ="TestButton1"
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
...
})
>
Add New {sectionInputArray.name}
</button>
<button
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
..
})
>
Remove {sectionInputArray.name}
</button>
</>
)}
</section>
</>
);

If the content the same you could use Fragments and conditionally show the buttons:
return (
<>
<section
className={`col-md-${sectionInputArray.width} justify-content border-end mt-2 mb-2`}
>
<h4 className="border-bottom">{`${sectionInputArray.name}`} </h4>
<div className="col-12"></div>
{sectionInputArray.contents.map((input, i) => (
<NestedDynamicInputCreation
singleInput={input}
formData={formData}
setFormData={setFormData}
options={options}
mode={mode}
staticVars={staticVars}
SetStaticVars={SetStaticVars}
i={i}
idx={idx}
arrayLength={arrayLength}
sectionUID={sectionInputArray.UID}
/>
))}
{mode !== 'view' && (
<>
<button
id ="TestButton1"
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
// console.log(`${sectionInputArray.name} section will be added`);
// console.log({ formDataTarget: formData[sectionInputArray.UID] });
// New Inbound Rule
// console.log([
// ...formData[sectionInputArray.UID],
// NestedListIDSingle(sectionInputArray),
// ]);
let addedFormData = {
...formData,
[`${sectionInputArray.UID}`]: [
...formData[sectionInputArray.UID],
NestedListIDSingle(sectionInputArray),
],
};
let randomVal = Math.random()
.toString(36)
// .replace(/[^a-z]+/g, "")
.substr(0, 11);
let withRandom = {
...addedFormData,
rand_value: randomVal,
};
// console.log({ addedFormData: addedFormData });
setFormData(withRandom);
}}
>
Add New {sectionInputArray.name}
</button>
{/* Button to remove section (or created form) */}
<button
className="btn btn-primary bt-btn m-3"
type="button"
onClick={() => {
console.log(
`${sectionInputArray.name}-${idx} section will be removed`
);
// formData[sectionInputArray.UID].splice(idx, 1);
let formDataTarget = formData[sectionInputArray.UID];
// console.log(formDataTarget);
let newFD = formData;
newFD[sectionInputArray.UID].splice(idx, 1);
let randomVal = Math.random()
.toString(36)
// .replace(/[^a-z]+/g, "")
.substr(0, 11);
let withRandom = {
...newFD,
rand_value: randomVal,
};
setFormData(withRandom);
}}
>
Remove {sectionInputArray.name}
</button>
</>
)}
</section>
</>
);

Related

Radio Button clicked value get the previous clicked value React

I have MUI radio buttons which I use to get filter criteria and I filter an object. Then i render the filtered object in an owl carousal to show. But when I click on a radio button it always takes the previously clicked value of the radio button. I have used ternary conditions to check but it keeps happening I couldb't figure out following is my code.
<FormControl>
<RadioGroup
row
aria-labelledby="demo-row-radio-buttons-group-label"
name="row-radio-buttons-group"
value={movieType}
onChange={movieTypeChange}
>
<FormControlLabel
value="1"
control={<Radio color="error" />}
label="All"
/>
<FormControlLabel
value="2"
control={<Radio color="error" />}
label="Now Showing"
/>
<FormControlLabel
value="3"
control={<Radio color="error" />}
label="Upcoming"
/>
</RadioGroup>
</FormControl>
{filterdMovie.length > 0 ? (
<OwlCarousel
className="owl-theme"
loop={movieCount}
center={movieCount}
margin={1}
autoplay={true}
dots={false}
items={3}
touchDrag={true}
lazyLoad={true}
responsive={state.responsive}
// responsive={"0:{items:1,},600:{items:3,},1000:{items:5,}"}
animateOut={"fadeOut"}
>
{filterdMovie.map((movieBannertop, idx) => {
return (
<div key={idx}>
<div className="item">
<div className="prs_upcom_movie_box_wrapper">
<div className="prs_upcom_movie_img_box">
<img
src={
movieBannertop.thumbnail
// HTMLImageElement.complete
// ?
// `${process.env.REACT_APP_DEV_BASE_URL_IMAGE}/movie/${movieBannertop.id}/thumbnail.jpg`
// : placeholder
}
alt="movie_img"
/>
<div className="prs_upcom_movie_img_overlay"></div>
<div className="prs_upcom_movie_img_btn_wrapper">
<ul>
<li>
{movieBannertop.bookingOpen ? (
<a
href
onClick={() => viewMovie(movieBannertop)}
style={{ textDecoration: "none" }}
>
More Info
</a>
) : null}
</li>
<li>
{!movieBannertop.upcoming ? (
<a
href
onClick={() => viewMovie(movieBannertop)}
style={{ textDecoration: "none" }}
>
Now Showing
</a>
) : (
<a
href
style={{
textDecoration: "none",
backgroundColor: "#2488ed",
}}
onClick={() => viewMovie(movieBannertop)}
>
Coming Soon
</a>
)}
</li>
</ul>
</div>
</div>
<div className="prs_upcom_movie_content_box">
<div className="prs_upcom_movie_content_box_inner">
<Tooltip title={movieBannertop.name}>
<h2>
<a
href
onClick={() => viewMovie(movieBannertop)}
style={{ textDecoration: "none" }}
>
{" "}
{movieBannertop.name.length > 10
? `${movieBannertop.name.substring(0, 10)}...`
: movieBannertop.name}
</a>
</h2>
</Tooltip>
<p>{movieBannertop.genre}</p>
</div>
<div className="prs_upcom_movie_content_box_inner_icon">
{/* <ul>
<li>
<a href="movie_booking.html">
<i className="flaticon-cart-of-ecommerce"></i>
</a>
</li>
</ul> */}
</div>
</div>
</div>
</div>
</div>
);
})}
</OwlCarousel>
) : (
<>
<Stack
direction="column"
justifyContent="center"
alignItems="center"
>
<img src={notFound} alt="" width="50%" />
<h4>No Movies Found</h4>
</Stack>
</>
)}
const movieTypeChange = (e) => {
e.preventDefault();
setMovieType(e.target.value);
const value = e.target.value;
if (value === "1") {
setFileredMovies(onlineMovies);
}
if (value === "2") {
let shows = [];
onlineMovies.forEach((element) => {
if (!element.upcoming) {
shows.push(element);
}
});
setFileredMovies(shows);
console.log(shows);
}
if (value === "3") {
console.log("3");
let shows = [];
onlineMovies.forEach((element) => {
if (element.upcoming) {
shows.push(element);
}
});
setFileredMovies(shows);
}
};
const movieTypeChange = (e) => {
var shows = [];
const value = e.target.value;
if (value === "1") {
setFileredMovies(onlineMovies);
}
if (value === "2") {
onlineMovies.forEach((element) => {
if (!element.upcoming) {
shows.push(element);
}
});
setFileredMovies(shows);
}
if (value === "3") {
onlineMovies.forEach((element) => {
if (element.upcoming) {
shows.push(element);
}
});
setFileredMovies(shows);
}
setMovieType(value);
};

How we handle modal in Ag Grid React in cellRendererFramework?

I have 2 buttons in Ag Grid table in Actions Column. How can I call function, on click of Approve Button in Modal ?
Thanks in Advance
PFB my code -
=>> Ag Grid Component =
const AgGridComp = () => {
const [tableData,setTableData] = useState([{"column1":"Value 1","column2":"Value 2"},{"column1":"Value 3","column2":"Value 4"}])
return(
<>
<div className="ag-grid-data">
<AgGridReact
rowData={tableData}>
<AgGridColumn field="column1" headerName="Column 1"></AgGridColumn>
<AgGridColumn field="column2" headerName="Column 2"></AgGridColumn>
<AgGridColumn headerName="Actions" cellRendererFramework={Actions}></AgGridColumn>
</AgGridReact>
</div>
</>
)
}
==>> Actions Code ==
const Actions = (props) => {
return(
<>
<button className="btn btn-success">Approve</button>
<button className="btn btn-danger">Reject</button>
</>
)
}
==>>Modal Code ==
const ActionsModal = () => {
return(
<>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-title">
<h4>Are you sure to Approve ?</h4>
</div>
<div className="modal-footer">
<button className="btn btn-default">Cancel</button>
<button className="btn btn-success">Approve</button>
</div>
</div>
</div>
</>
)
}

Bootstrap carousel: sets active item to first when data changes (Reactjs)

My carousel with data.img is an array of link img
<div
id="carouselExampleControls"
className="codeinfo__carousel carousel slide"
data-bs-ride="carousel"
>
<div className="carousel-inner">
<div className="carousel-item active">
<img
src={data.img[0]}
className="codeinfo__img d-block w-100"
alt="..."
/>
</div>
{data.img.map(
(e, i) =>
i > 1 && (
<div className="carousel-item">
<img
src={e}
className="codeinfo__img d-block w-100"
alt="..."
/>
{i}
</div>
)
)}
</div>
<button
className="carousel-control-prev"
type="button"
data-bs-target="#carouselExampleControls"
data-bs-slide="prev"
>
<span className="carousel-control-prev-icon" aria-hidden="true" />
<span className="visually-hidden">Previous</span>
</button>
<button
className="carousel-control-next"
type="button"
data-bs-target="#carouselExampleControls"
data-bs-slide="next"
>
<span className="carousel-control-next-icon" aria-hidden="true" />
<span className="visually-hidden">Next</span>
</button>
</div>
When the data has changed, the active item does not return to the first item, but to the number of the previous active item. So if the length of the previous data.img is bigger than the length of the current data.img there will be nothing to display and the carousel will crash.(sorry for my english, I use google translate)
Like the example below. How to make class "active" return first item?
carousel1 > Change data > carousel2
I solved the problem myself. I removed all bootstrap actions and select active item using react code. I use useState to select active item, setInterval to autoPlay, useEffect to reset activity to 0. Here is my code:
const Carousel = (props) => {
const data = props.data;
const [nowActive, setNowActive] = useState(0);
const [onHover, setOnHover] = useState(false);
// autoplay (stop in hover)
useEffect(() => {
if (!onHover && data !== null) {
let i = nowActive;
const timer = setInterval(() => {
if (i >= data.img.length - 1) {
setNowActive(0);
i = 1;
} else {
setNowActive((prev) => prev + 1);
i = i + 1;
}
}, 3000);
return () => {
clearTimeout(timer);
};
}
}, [onHover, data]);
// change data >> return active = 0
useEffect(() => {
setNowActive(0);
}, [data]);
const carousel = () => {
return (
<div
id="carouselExampleControls"
className="codeinfo__carousel carousel slide"
data-bs-ride="carousel"
onMouseOver={() => setOnHover(true)}
onMouseLeave={() => setOnHover(false)}
>
<div className="carousel-inner">
{data.img.map((e, i) => (
<div className={"carousel-item " + (nowActive === i && "active")}>
<img src={e} className="codeinfo__img d-block w-100" alt="..." />
</div>
))}
</div>
<button
className="carousel-control-prev"
type="button"
onClick={() => {
nowActive === 0
? setNowActive(data.img.length - 1)
: setNowActive(nowActive - 1);
}}
>
<span className="carousel-control-prev-icon" aria-hidden="true" />
<span className="visually-hidden">Previous</span>
</button>
<button
className="carousel-control-next"
type="button"
onClick={() => {
nowActive === data.img.length - 1
? setNowActive(0)
: setNowActive(nowActive + 1);
}}
>
<span className="carousel-control-next-icon" aria-hidden="true" />
<span className="visually-hidden">Next</span>
</button>
</div>
);
};
return data !== null ?
<div>{carousel()}</div> :
<div>Null data</div>
Note: Although the problem has been solved, but this carousel does not have any Animation Effect when changing slides:
Carousel has a property called defaultActiveIndex, which is the initial value of activeIndex. You can use it to focus on the correct CarouselItem
Create a new State:
const [activeIndex, setActiveIndex] = useState(0);
Set the defaultActiveIndex to the newly created state:
Change the activeIndex whenever an item in the carousel is clicked:
onClick={(e) => { setActiveIndex(i); }}
Honestly they should just make this default behavior, not sure why we have to hack it.

React Buttons and State - how to avoid too many States?

I am still somewhat of a novice to React with much to learn. At the moment I am trying to make a page displaying lightsabers and hilts from Star Wars by clicking a button to show the ones you want. I am doing this by using State, which by the amount of states I currently have seems like the wrong way of doing it.
Here's how I'm doing it: I set a State and put an onClick event that sets the chosen hilt/color to true and the rest to false whilst also rendering information of said hilt/color. It looks like this:
import { ReactComponent as QuiGon } from './qui-gon.svg';
import { ReactComponent as ObiWan } from './obi-wan.svg';
import { ReactComponent as ObiWanOld } from './obi-hilt-old.svg';
import { ReactComponent as DarthMaul } from './darth-maul-hilt.svg';
import { ReactComponent as AhsokaHilt } from './ahsoka-hilt.svg';
import { ReactComponent as AnakinHilt } from './anakin-hilt.svg';
import { ReactComponent as VaderHilt } from './darth-vader-hilt.svg';
import { ReactComponent as KyloHilt } from './kylo-ren-hilt.svg';
import './App.css';
function App() {
const [nonChosen, setNonChosen] = useState(true);
const [blue, setBlue] = useState(false);
const [red, setRed] = useState(false);
const [green, setGreen] = useState(false);
const [purple, setPurple] = useState(false);
const [yellow, setYellow] = useState(false);
const [white, setWhite] = useState(false);
const [saberOne, setSaberOne] = useState(true);
const [doubleSaber, setDoubleSaber] = useState(false);
const [quiGon, setQuiGon] = useState(false);
const [obiWanNew, setObiWanNew] = useState(false);
const [obiWanOld, setObiWanOld] = useState(false);
const [ahsoka, setAhsoka] = useState(false);
const [anakinHilt, setAnakinHilt] = useState(false);
const [vaderHilt, setVaderHilt] = useState(false);
const [kyloHilt, setKyloHilt] = useState(false);
return (
<div className="App">
{/* Colors */}
<button className="testsub" onClick={() => {setGreen(true); setWhite(false); setYellow(false); setPurple(false); setRed(false); setBlue(false); setNonChosen(false);}}>Green
</button>
<button className="testsub" onClick={() => {setBlue(true); setWhite(false); setYellow(false); setPurple(false); setRed(false); setGreen(false); setNonChosen(false);}}>Blue
</button>
<button className="testsub" onClick={() => {setRed(true); setWhite(false); setYellow(false); setPurple(false); setBlue(false); setGreen(false); setNonChosen(false);}}>Red
</button>
<button className="testsub" onClick={() => {setPurple(true); setWhite(false); setYellow(false); setGreen(false); setRed(false); setBlue(false); setNonChosen(false);}}>Purple
</button>
<button className="testsub" onClick={() => {setYellow(true); setWhite(false); setPurple(false); setGreen(false); setRed(false); setBlue(false); setNonChosen(false);}}>Yellow
</button>
<button className="testsub" onClick={() => {setWhite(true); setYellow(false); setPurple(false); setGreen(false); setRed(false); setBlue(false); setNonChosen(false);}}>White
</button>
<br />
{/* Hilts */}
<button className="testsub" onClick={() => {setDoubleSaber(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false); setObiWanOld(false);}}>Darth Maul
</button>
<button className="testsub" onClick={() => {setQuiGon(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setObiWanNew(false); setObiWanOld(false);}}>Qui Gon
</button>
<button className="testsub" onClick={() => {setObiWanNew(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanOld(false);}}>Obi Wan
</button>
<button className="testsub" onClick={() => {setObiWanOld(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Obi Wan Old
</button>
<button className="testsub" onClick={() => {setAhsoka(true); setKyloHilt(false); setVaderHilt(false); setAnakinHilt(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Ahsoka Tano
</button>
<button className="testsub" onClick={() => {setAnakinHilt(true); setKyloHilt(false); setVaderHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Anakin
</button>
<button className="testsub" onClick={() => {setVaderHilt(true); setKyloHilt(false); setAnakinHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Vader
</button>
<button className="testsub" onClick={() => { setKyloHilt(true);setVaderHilt(false); setAnakinHilt(false); setAhsoka(false); setObiWanOld(false); setDoubleSaber(false); setSaberOne(false); setQuiGon(false); setObiWanNew(false);}}>Kylo
</button>
<div class="lightsaber">
<input type="checkbox" id="on-off" />
{nonChosen && (
<>
<div className="blade colol"></div>
{/* <div className="blade2 colol"></div> */}
</>
)}
{blue && (
<div className="blade colol2"></div>
)}
{red && (
<div className="blade red-clr"></div>
)}
{green && (
<div className="blade colol"></div>
)}
{purple && (
<div className="blade purple-clr"></div>
)}
{yellow && (
<div className="blade yellow-clr"></div>
)}
{white && (
<div className="blade white-clr"></div>
)}
{saberOne && (
<label className="hilt" for="on-off">
<QuiGon />
</label>
)}
{doubleSaber && (
<>
<div className="blade2 colol"></div>
<label className="hilt" for="on-off">
<DarthMaul />
</label>
</>
)}
{quiGon && (
<label className="hilt" for="on-off">
<QuiGon />
</label>
)}
{obiWanNew && (
<label className="hilt" for="on-off">
<ObiWan />
</label>
)}
{obiWanOld && (
<label className="hilt" for="on-off">
<ObiWanOld />
</label>
)}
{ahsoka && (
<label className="hilt" for="on-off">
<AhsokaHilt />
</label>
)}
{anakinHilt && (
<label className="hilt" for="on-off">
<AnakinHilt />
</label>
)}
{vaderHilt && (
<label className="hilt" for="on-off">
<VaderHilt />
</label>
)}
{kyloHilt && (
// <label className="hilt" for="on-off">
// <KyloHilt className="hilt2"/>
// </label>
<>
<div className="blade3 colol"></div>
<div className="blade4 colol"></div>
<label className="hilt" for="on-off">
<KyloHilt className="hilt2"/>
</label>
</>
)}
</div>
<div className="infobox">
{nonChosen && (
<div>Yoyoyo</div>
)}
{blue && (
<div>aasdsd</div>
)}
{green && (
<div>fgfgfg</div>
)}
</div>
</div>
);
}
export default App;
It is not completed hence a bit messy, but the problem shows quite nice. I have a lot of States and the buttons gets quite long with all the setX(false).
Is there any way to do this in a better way? I've been pondering for a long time about doing it pure CSS, with if/else etc. but I can't seem to wrap my head around how go get the button to display one thing and leave the rest hidden without having to over-specify it like I already am. Again I am still a novice, so any help would really be appreciated (and again sorry for the spaghetti code)!
You can initialize the values in an object and use them as initial state
const initialValues = {
nonChosen: true,
blue: false,
red: false,
green: false,
purple: false,
yellow: false,
white: false,
// All other states in this or create a seperate object with seperate useState according to your wish
};
And initialize the state as
const [colors, setColors] = useState(initialValues);
Setting the value during onClick as
<button className="testsub" onClick={() => {setColors({...colors,green:true,white:false,yellow:false,purple:false,red:false,blue:false,nonchosen:false})>Green</button>
During rendering:
{colors.nonChosen && (
<>
<div className="blade colol"></div>
{/* <div className="blade2 colol"></div> */}
</>
)}
You can use useReducer hook.
Also, you can inline event (for color) or callback event (for hilt).
I used two cases.
const initialColorState = {
nonChosen: false,
blue: false,
red: false,
green: false,
purple: false,
yellow: false,
white: false,
};
const initialHiltState = {
saberOne: false,
doubleSaber: false,
quiGon: false,
obiWanNew: false,
obiWanOld: false,
ahsoka: false,
anakinHilt: false,
vaderHilt: false,
kyloHilt: false
}
function colorReducer(state, action) {
switch (action.type) {
case "Blue": {
return {
...state,
...initialColorState,
blue: true,
}
}
case "Red": {
return {
...state,
...initialColorState,
red: true,
}
}
case "Green": {
return {
...state,
...initialColorState,
green: true,
}
}
case "Purple": {
return {
...state,
...initialColorState,
purple: true,
}
}
case "Yellow": {
return {
...state,
...initialColorState,
yellow: true,
}
}
case "White": {
return {
...state,
...initialColorState,
white: true,
}
}
}
}
function hiltReducer(state, action) {
switch (action.type) {
case "DoubleSaber": {
return {
...state,
...initialHiltState,
doubleSaber: true,
}
}
case "QuiGon": {
return {
...state,
...initialHiltState,
quiGon: true,
}
}
case "ObiWanNew": {
return {
...state,
...initialHiltState,
obiWanNew: true,
}
}
case "ObiWanOld": {
return {
...state,
...initialHiltState,
obiWanOld: true,
}
}
case "Ahsoka": {
return {
...state,
...initialHiltState,
ahsoka: true,
}
}
case "Anakin": {
return {
...state,
...initialHiltState,
anakinHilt: true,
}
}
case "Vader": {
return {
...state,
...initialHiltState,
vaderHilt: true,
}
}
case "Kylo": {
return {
...state,
...initialHiltState,
kyloHilt: true,
}
}
}
}
function App() {
const [colorState, colorDispatch] = useReducer(colorReducer, initialColorState)
const [hiltState, hiltDispatch] = useReducer(hiltReducer, initialHiltState);
const onHiltClick = useCallback((event) => {
hiltDispatch({type: event.value});
}, [hiltDispatch]);
return (
<div className="App">
{/* Colors */}
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "Green" })
}}
>
Green
</button>
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "Blue" })
}}
>
Blue
</button>
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "Red" })
}}
>
Red
</button>
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "Purple" })
}}
>
Purple
</button>
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "Yellow" })
}}
>
Yellow
</button>
<button
className="testsub"
onClick={() => {
colorDispatch({ type: "White" })
}}
>
White
</button>
<br />
{/* Hilts */}
<button className="testsub" onClick={onHiltClick} value="DoubleSaber">
Darth Maul
</button>
<button className="testsub" onClick={onHiltClick} value="QuiGon">
Qui Gon
</button>
<button className="testsub" onClick={onHiltClick} value="ObiWanNew">
Obi Wan
</button>
<button className="testsub" onClick={onHiltClick} value="ObiWanOld">
Obi Wan Old
</button>
<button className="testsub" onClick={onHiltClick} value="Ahsoka">
Ahsoka Tano
</button>
<button className="testsub" onClick={onHiltClick} value="Anakin">
Anakin
</button>
<button className="testsub" onClick={onHiltClick} value="Vader">
Vader
</button>
<button className="testsub" onClick={onHiltClick} value="Kylo">
Kylo
</button>
.....
)
}
export default App;

React, how to assign a user to the button, to block a user?

I got list of users and next to each user there is block button.
After clicking on a block button, a modal pops up asking for confirmation. When i confirm, specific user is being block.
Now i got displaying modal but after clicking on confirm button nothing happens.
I think I need to assign a user to the button?
Unlock button works, but it's not in a modal.
My code:
import MyModal from '#/views/MyModal'
function UsersList({ users, userId }) {
function locking(pk, action) {
axios.get(`/user/${pk}/${action}/`).then(() => {
update()
})
}
return (
...{users != null && users.length > 0 ? (
users.map((profile) => {
return (
<tr key={profile.id} id={profile.id} className={userId === profile.id ? 'table-active' : ''}>
{showEntities && <td className='align-middle'>{profile.entity_name}</td>}
<td className='align-middle'>
{profile.first_name} {profile.last_name}
{!profile.active && (
<span className='ml-xl-2 badge badge-pill badge-secondary'>
<i className='fa fa-lock' /> Blocked
</span>
)}
</td>...
{profile.id !== userId && //to be sure to not block myself
(profile.active ? (
<button
type='button'
className='btn d-block btn-danger w-5rem mb-2 badge'
data-toggle='modal'
data-target='#MyModal'
>
Block
</button>
) : (
<a
className='btn d-block btn-warning w-5rem mb-2 badge'
href='#'
onClick={() => {
locking(profile.id, 'unlock')
}}
>
Unblock
</a>
))}
</td>
</tr>
)
})
) : (
)}
</tbody>
</table>
<MyModal locking={locking()} />
</div>
)
}
export default UsersList
MyModal
export default function MyModal({locking}) {
return (
<div className='modal fade' id='MyModal' tabIndex='-1' aria-labelledby='MyModal' aria-hidden='true'>
...
<h5 className='modal-title' id='MyModal'>
Are you sure to block this user?
</h5>
<button type='button' className='close' data-dismiss='modal' aria-label='Close'>
<span aria-hidden='true'>×</span>
</button>
</div>
<div className='modal-footer'>
<button type='button' className='btn btn-default' data-dismiss='modal'>
<i className='fas fa-times mr-2' />
Exit
</button>
<button
type='button'
className='btn btn-success'
onClick={() => {
locking
}}
>
<i className='fas fa-check-circle mr-2' />
Confirm
</button>
</div>
</div>
</div>
</div>
)
}
Issues
There is no click handler to block a profile
When passing locking to MyModal it is invoked immediately (locking={locking()})
In the MyModal block button onClick callback locking isn't invoked (() => { locking }
Solution
Add some state to UserList to store a user/profile id to block/unblock
Create a block callback to pass to the modal
Pass block callback to MyModal
UsersList
function UsersList({ users, userId }) {
const [profileId, setProfileId] = useState(null); // <-- create id state
function locking(pk, action) {
axios.get(`/user/${pk}/${action}/`)
.then(() => {
update();
})
.finally(() => {
setProfileId(null); // <-- clear state when done
});
}
const blockId = () => locking(profileId, 'lock'); // <-- callback to block/lock
return (
...
{users != null && users.length > 0 ? (
users.map((profile) => {
return (
<tr key={profile.id} id={profile.id} className={userId === profile.id ? 'table-active' : ''}>
...
</td>
...
{profile.id !== userId && //to be sure to not block myself
(profile.active ? (
<button
type='button'
className='btn d-block btn-danger w-5rem mb-2 badge'
data-toggle='modal'
data-target='#MyModal'
onClick={() => setProfileId(profile.id)} // <-- set id to block
>
Block
</button>
) : (
<a
className='btn d-block btn-warning w-5rem mb-2 badge'
href='#'
onClick={() => {
locking(profile.id, 'unlock')
}}
>
Unblock
</a>
))}
</td>
</tr>
)
})
) : (
)}
</tbody>
</table>
<MyModal locking={blockId} /> // <-- pass blockId callback
</div>
)
}
MyModal
export default function MyModal({locking}) {
return (
<div className='modal fade' id='MyModal' tabIndex='-1' aria-labelledby='MyModal' aria-hidden='true'>
...
<button
type='button'
className='btn btn-success'
onClick={locking} // <-- attach callback
>
<i className='fas fa-check-circle mr-2' />
Confirm
</button>
...
</div>
)
}

Resources