React. Refresh parent component on button click - reactjs

How to reload/refresh a parent component on button click.
In the code below i refresh page with javascript vanilla (window.location.reload(false)
Is there a way to reload the parent component or page without refreshing the page?
return product ? (
<div>
<div>
<img src={product.images[0]} alt={product.title} />
</div>
<div>
{product.title}
<br />
${product.price}
<br />
{product.description}
</div>
<div>
<button onClick={
() => {
setLiked(!liked)
if (favProduct) {
window.location.reload(false)
}
}
}>
<Icon size="28px" />
</button>
</div>
</div>
) : <p>Loading Product... </p>;

Not sure why you would want to do something like that, but here is one way to do it:
const Parent = () => {
const [toggleRefresh, setToggleRefresh] = useState(false)
return (
<Child setToggleRefresh={setToggleRefresh}/>
)
}
const Child = (props) => {
return (
<button onClick={
() => {
setLiked(!liked)
if (favProduct) {
//this will toggle the state of the parent, forcing a parent rerender
props.setToggleRefresh(prev => !prev)
}
}
}>
)
}

Related

React.js close all the previous containers at the same time

I got the container with children coming from props.[Container][1]
[1]: https://i.stack.imgur.com/3Y7Qm.png . When i click the arrow button it shows the content of the container. [Content][1]
[1]: https://i.stack.imgur.com/A8eZH.png . When i open the content container i want other containers to close . For now i can only close them with clicking the arrow button again.[Open Content][1]
[1]: https://i.stack.imgur.com/REh57.png .Here is my code `
import { useState } from "react";
export default function Question(props) {
const [clicked, setClicked] = useState(false);
function clickedElement() {
return setClicked(!clicked);
}
return (
<div className="question-cont">
<div className="question-cont-inner">
<h3>{props.head}</h3>
<button onClick={() => clickedElement()}>
{clicked ? (
<img src={props.img2} />
) : (
<img src={props.img} />
)}{" "}
</button>
</div>
{clicked ? <p>{props.description}</p> : ""}
</div>
);
}
Here is the my parent component
import Question from "../components/Question";
import questions from "../components/Questions";
export default function Sorular() {
const questionList = questions.map((question) => {
return (
<Question
key={question.id}
id={question.id}
head={question.head}
description={question.description}
img={question.img}
img2={question.img2}
/>
);
});
return (
<div className="sorular-container">
<div className="sorular-top">
<div className="sorular-top-back-img">
<a href="/">
<img
src="./images/right-arrow-colorful.png"
id="right-arrow-img"
/>
</a>
</div>
<div className="sorular-top-head">
<img src="./images/conversation.png" />
<h4>Sıkça Sorulan Sorular</h4>
</div>
</div>
<div className="sorular-bottom">{questionList}</div>
</div>
);
}
`
You need to remove your const [clicked, setClicked] = useState(false); state variable from the component itself and move it into parent:
In parent add this at the beggining and modify questionList:
const [clickedElementId, setClickedElementId] = useState(null);
const questionList = questions.map((question) => {
return (
<Question
key={question.id}
id={question.id}
head={question.head}
description={question.description}
img={question.img}
img2={question.img2}
isOpened={question.id === clickedElementId}
onClickedElement={() => setClickedElementId(
question.id === clickedElementId ? null : question.id
)}
/>
);
});
And in the Question.jsx, swap button for the following:
<button onClick={() => props.onClickedElement()}>
{props.isOpened ? (
<img src={props.img2} />
) : (
<img src={props.img} />
)}{" "}
</button>
// and later:
{props.isOpened ? <p>{props.description}</p> : ""}
This works by your app holding id of only one, currently open question, and swap it based on clicked element.
Note that questionId should be unique amongst all Question components, but you probably use .map to render them so you should use the same variable as you are passing into Question's key prop while rendering.

React: Child don't update parent's state

I'm new to React and I was trying to create a Modal using mui that opens and closes based on parent's state.
The problem is that the modal opens well based on state but upon closing, the modal onClose function works well, but when I click on Button that has the same with the same update state function it doesn't work.
Here's my parent component
const TableIcon = props => {
const {title,icon}=props;
// handling modal functionality
const [modalOpen, setModalOpen] = useState(false);
const handleModalOpen = () => {
setModalOpen(true);
};
const handleModalClose = () => {
setModalOpen(false);
};
console.log('modal', modalOpen)
return (
<button className={styles.button} title={title} onClick={()=>handleModalOpen()}>
{icon}
<ActionModal
open={modalOpen}
handleClose={handleModalClose}
handleOpen={handleModalOpen}
/>
</button>
)
}
and here is the modal component
const ActionModal=(props)=> {
const {open,handleOpen,handleClose}=props;
console.log(props,'modal')
return (
<div>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box className={styles.box}>
<div className={styles.header}>
<div className={styles.icon}>
<BsFillTrashFill/>
</div>
</div>
<div className={styles.content}>
<h2>You are about to delete a school</h2>
<h3>School Name/Tuituion</h3>
<p>This will delete the school from the database
Are you sure?</p>
</div>
<div className={styles.footer}>
<Button color='var(--unnamed-color-ffffff)' name='Cancel' onClick={handleClose}/>
<Button color='var(--unnamed-color-f53748)' name='Confirm'/>
</div>
</Box>
</Modal>
</div>
);
}
and here is the button component
const Button=(props)=>{
const {color,onClick,icon,name}=props;
return <div className={styles.container} style={{background:color}} onClick={()=>onClick()}>
{icon}
<span>{name}</span>
</div>
}
and the Button onClick works just fine
The problem is that your <ActionModal> component is inside the <button> tag. So when clicking the Cancel button in the modal you first get the call to handleModalClose, immediately followed by the call to handleModalOpen, because the "click" is getting passed to the button that opens the modal.
You need to change the code in <TableIcon> to something like:
return (
<>
<button title={title} onClick={() => handleModalOpen()}>
{icon}
</button>
<ActionModal open={modalOpen} handleClose={handleModalClose} />
</>
);
You can use this Stackblitz example.

How to change a style of an HTML element in React?

I have two React components
class App extends React.Component {
render() {
return (
<div id="appWrapper">
<ConfigureWindow />
<button id="configureClocksButton">Configure clocks</button>
<section id="clocksHere"></section>
</div>
);
}
}
const ConfigureWindow = () => (
<div id="configureWindowWrapper">
<div id="configureWindow">
<section id="addCitySection">TODO: adding a city</section>
<div id="verticalLine"></div>
<section id="listOfCities">
<header>
<h1>Available cities</h1>
<div id="closeConfigureWindowWrapper">
<img src="..\src\images\exit.png" id="closeConfigureWindow" alt="" />
</div>
</header>
<section id="availableCities"></section>
</section>
</div>
</div>
);
I want "ConfigureWindow" to be shown when "configureClocksButton". I tried to execute it with props, state and a function but got errors. It also would be nice if you explain me how to create new React components with React functions?
You probably want to use the React.JS event onClick (https://reactjs.org/docs/handling-events.html), and a state to store the action. To create a function component, you just have to return the JSX you want to render, and use hooks (https://reactjs.org/docs/hooks-intro.html) and then do a conditional rendering (https://reactjs.org/docs/conditional-rendering.html):
const App = () => {
const [toggleConfiguration, setToggleConfiguration] = useState(false)
return (
<div id="appWrapper">
{toggleConfiguration && <ConfigureWindow />}
<button onClick{() => setToggleConfiguration(true)} id="configureClocksButton">Configure clocks</button>
<section id="clocksHere"></section>
</div>
);
}
It's a bit difficult to understand your post, but I gather you want to click the button with id="configureClocksButton" and conditionally render the ConfigureWindow component.
You can accomplish this with some boolean state, a click handler to toggle the state, and some conditional rendering.
class App extends React.Component {
this.state = {
showConfigureWindow: false,
}
toggleShowConfigureWindow = () => this.setState(prevState => ({
showConfigureWindow: !prevState.showConfigureWindow,
}))
render() {
return (
<div id="appWrapper">
{showConfigureWindow && <ConfigureWindow />}
<button
id="configureClocksButton"
onClick={this.toggleShowConfigureWindow}
>
Configure clocks
</button>
<section id="clocksHere"></section>
</div>
);
}
}
A function component equivalent:
const App = () => {
const [showConfigureWindow, setShowConfigureWindow] = React.useState(false);
const toggleShowConfigureWindow = () => setShowConfigureWindow(show => !show);
return (
<div id="appWrapper">
{showConfigureWindow && <ConfigureWindow />}
<button
id="configureClocksButton"
onClick={toggleShowConfigureWindow}
>
Configure clocks
</button>
<section id="clocksHere"></section>
</div>
);
}

Share state between components in React

I'm trying to make a dashboard using React. There are few components: App, Block and other child components, let's call them Content.
Block is a simple bootstrap card with title, classes and some css.
In App I call Block and pass in the Content components.
But in some Content components there are functions, which can change Block component (e.g. add or remove classes).
Now I use states in App and Content components to change Block, but I don't think this is the right approach.
Adding setState in Block component is impossible, as I know, because there is no way to change props.
How can I change Block states from within Content components?
Example:
function App() {
return (
<div>
<Block
id="users-component"
title="Users Table"
classes=[]
content={
<MyTable class="users" />
}
/>
<Block
id="status-component"
title="Status Component"
classes=[]
content={
<Status class="status" />
}
/>
<Block
id="bdays-component"
title="Bdays Component"
classes=[]
content={
<Bdays class="bdays" />
}
/>
</div>
)
}
function Block(props) {
return (
<div id={props.id} className={props.classes.join(" ")}>
<h2>{props.title}</h2>
{props.content}
</div>
)
}
function MyTable(props) {
return (
<table className={props.class}></table>
)
}
function Status(props) {
const handleClick = (title) => {
changeTitle(title) // changes title in Block
}
return (
<div className={props.class}>
<button onClick={() => handleClick("newTitle")}>New Title</button>
</div>
)
}
function Bdays(props) {
const handleClick = (class) => {
addNewClass(class) // add new class to array "classes" in it's block
}
return (
<div className={props.class}>
<button onClick={() => handleClick("newClass")}>New Class</button>
</div>
)
}
P.S. Sorry for my English)
Problem is solved by moving Content components into Block body and using React.cloneElement. Now, it's look like this:
function App() {
return (
<div>
<Block
id="users-component"
title="Users Table"
>
<MyTable class="users" />
</Block>
<Block
id="status-component"
title="Status Component"
>
<Status class="status" />
</Block>
<Block
id="bdays-component"
title="Bdays Component"
>
<Bdays class="bdays" />
</Block>
</div>
)
}
function Block(props) {
[classes, addClasses] = useState([""])
[title, renewTitle] = useState(props.title)
return (
<div id={props.id} className={classes.join(" ")}>
<h2>{props.title}</h2>
{React.cloneElement(children, {addClasses, renewTitle})}
</div>
)
}
function MyTable(props) {
return (
<table> </table>
)
}
function Status(props) {
const handleClick = (title) => {
props.renewTitle(title) // changes title in Block
}
return (
<div>
<button onClick={() => handleClick("newTitle")}>New Title</button>
</div>
)
}
function Bdays(props) {
const handleClick = (class) => {
props.addClasses([class]) // add new class to array "classes" in it's block
}
return (
<div className={props.class}>
<button onClick={() => handleClick("newClass")}>New Class</button>
</div>
)
}
Doing it that way, you won't be able to share state between those components, since they're siblings (although I might get corrected on that)
You could instead, make myTable to be a child of Block, and pass a useState function TO myTable as a prop, that way you can change the state of Block from myTable
This is a sample implementation
import { useState } from "react";
export default function App() {
return (
<Block
id="users-component"
content={
<MyTable class="users" />
}
/>
);
}
function Block(props) {
const [headerText, setHeaderText] = useState("Marco!")
return (
<div id={props.id}>
<h1> {headerText} </h1>
<MyTable changeHeaderText = {setHeaderText} />
</div>
)
}
function MyTable(props) {
return (
<table className={props.class}>
<tbody>
<tr>
<td>
I'm a table and I can change my parent's header text!
</td>
</tr>
<tr>
<td>
<button
onClick = {() => props.changeHeaderText("polo!")} >Click me!</button>
</td>
</tr>
</tbody>
</table>
)
}

How on click rerender conmponent in react

When I click on a card, the loadAboutInfo function works through which I transfer data to another component and display it there. But if I click again on the same card, then it is duplicated. How can I fix it?I have check which take card id and then if it the same it render but I click again it render one more card, but i need if it already exist than new card mustn't render
loadAboutInfo=(pokemonValue,pockemonImg,pokemonId)=>{
this.setState(prevState => ({
pokemonValue:[...prevState.pokemonValue, pokemonValue],
pockemonImg,
pokemonId
}))
}
render() {
return (
<div className="wrapper">
<div className="pokemonlist__inner__cards">
<div className="pokemonlist__cards">
{this.state.pokemonList.map((value,index)=>{
let pokemonImgTemplate = this.state.pokemonImgTemplate;
let pokemonId = value.id;
let pockemonImg = pokemonImgTemplate.replace('{id}',pokemonId);
return(
<div className="pokemonListCard" key={index} onClick={()=>this.loadAboutInfo(value,pockemonImg,pokemonId)}>
<PokemonCard
pockemonImg={pockemonImg}
pokemonName={value.name}
pokemonTypes={value.types}
/>
</div>
)
})}
</div>
<PokemonLoadMore
loadMore={this.loadMore}
currentPage={this.state.currentPage}
/>
</div>
</div>
);
}
}
component where i map get data
render() {
return (
<div className="pokemon__about">
{this.props.pokemonValue.map((value,index)=>{
let totalMoves = value.moves.length;
return(
<div className="pokemon__about__wrapper" key={index}>
{this.props.pokemonId == value.id ?
<div className="pokemon__about__inner" key={index}>
<AboutImage
pockemonImg={this.props.pockemonImg}
/>
<AboutName
pockemonName={value.name}
/>
<div className="pokemon__about__table">
<AboutPokemonTypes
pokemonTypes={value.types}
/>
<table>
<AboutPokemonWeight
pockemonWeight={value.weight}
/>
<AboutPokemonMoves
totalMoves={totalMoves}
/>
</table>
</div>
</div>
:
null
}
</div>
)
})}
</div>
);
On the loadAboutInfo you can check if there is already a pokemon with the same id on pokemonValue array, something like this:
loadAboutInfo = (pokemonValue,pockemonImg,pokemonId) => {
// this will get the first element that matches the id
const exists = this.state.pokemonValue.find(pokemon => pokemon.id === pokemonId)
if (!exists) {
this.setState(prevState => ({
pokemonValue:[...prevState.pokemonValue, pokemonValue],
pockemonImg,
pokemonId
}))
}
}
So it will update the state only if the clicked pokemon isn't in the pokemonValue array

Resources