How to implement conditional rendering in React Reusable Component? - javascript

I have this reusable component where I would like to pass a value through that if true: a button is returned and if the value is false: the button doesn't render. I can't figure out how to do this using reusable components. The boolean variable I want to use is displayButton where if it is true, then the button is rendered and if it is false then the button is not rendered.
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
//if display button = true, display this button, if false, button is not displayed
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
<h4>{purchased}</h4>
</div>
);
};
export default Test;
Any help would very appreciated!

const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
{displayButton &&
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
}
<h4>{purchased}</h4>
</div>
);
};
export default Test;
if displayButton has the value of true it will render the button otherwise not

This will work.
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData">
<h5>{name}</h5>
<p>Cost: {value}</p>
{ displayButton &&
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
}
<h4>{purchased}</h4>
</div>
);
};
export default Test;

You can create a ShowHide component which can be utilized for conditional-rendering instead of having logical operators in every JSX where you need to conditionally render.
// create a ShowHide component
const ShowHide = ({show,children} ) => show && children
// your Test component with the button wrapped in ShowHide
const Test = ({ name, value, onClick, purchased, displayButton }) => {
return (
<div class="cardData card col-6 m-3">
<h5>{name}</h5>
<p>Cost: {value}</p>
<ShowHide show={displayButton}>
<button
type="button"
onClick={onClick}
class="btn btn-primary"
value={value}
name={name}
>
Purchase
</button>
</ShowHide>
<h4>{purchased}</h4>
</div>
);
};
const root = document.getElementById('root');
ReactDOM.render(
<Test name="My Card"
value="250,000"
onClick={() => alert('clicked')}
purchased="Yes!"
displayButton={false}
/>,
root
)
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Good Luck...

Related

How to access function component's state variables in ReactJS?

I've been developing a website and I'm faced with an issue about accessing state varibles to a component. I've a address page(Addresses.jsx file) which has address modal. I'm also have a component which contains address modal's content (Address.jsx). I would like to access state inside Address.jsx file. How can I do that? If you can help me. I would be very appreciate.
Here is my code blocks;
Address.jsx file;
const Addresses = () => {
const [selectedAddress, setSelectedAddress] = useState();
const [modalType, setModalType] = useState();
const {
elementRef: addressModalRef,
show: showAddressModal,
hide: hideAddressModal,
} = useModal();
return (
<>
<div className="bg-light px-3 px-lg-4 py-4">
<h1 className="h4 mb-4">My Addresses</h1>
<div className="row g-3">
<div className="col-12 col-md-6 col-lg-4">
<AddressButton
onClick={() => {
setSelectedAddress(undefined);
setModalType("NewAddress");
showAddressModal();
}}
/>
</div>
{ADDRESSES.map((address, i) => (
<div className="col-12 col-md-6 col-lg-4" key={i}>
<AddressButton
{...address}
onClick={() => {
setSelectedAddress(address);
setModalType("EditAddress");
showAddressModal();
}}
/>
</div>
))}
</div>
</div>
<AddressModal
address={selectedAddress}
elementRef={addressModalRef}
hide={hideAddressModal}
modalType={modalType}
/>
</>)};
export default Addresses;
Address Modal file;
const AddressModal = ({ address, elementRef, hide, modalType }) => {
const onSaveAddress = () => {
console.log(address);
hide();
};
return (
<Modal elementRef={elementRef} centered size="lg" fullscreen>
<ModalBody>
<AddressForm address={address} /> // I would like to get this component's state in onSaveAddress funtion
</ModalBody>
<ModalFooter>
<button
type="button"
className="btn btn-primary flex-grow-1 px-5"
onClick={onSaveAddress}>
Kaydet
</button>
</ModalFooter>
</Modal>)};
export default AddressModal;
Instead of accessing child components state, which is not possible, do the following
Address Model
<AddressForm
address={address}
onSave={onSaveAddress}
/>
Address Form
const AddressForm = ({ onSave }) => {
const handleFormSubmit = () => {
onSave(formData);
};
return (
<form onSubmit={handleFormSubmit}>
</form>
);
}
Then in onSaveAddress, you will have access to the form data.

How to render a react component and replicate them from the click event

I want to make multiple copies of Form2 React Component with click event, but the code not working as I want, I am new in react so can anybody help me.
const Comform = () => {
const Form2 = () => {
return(
<div className="card" id='form-card2'>
<input className="form-check-input" type="checkbox" value="" id="options-check" onClick={Optionscheck} />
</div>
);
}
const Replica = () {
<Form2/>
}
return(
<button type="button" className="btn btn-success" onClick={Replica}>Add</button>
);
}
Keep a state as the replica counter and render the number of items you want using Array.from and Array.prototype.map.
Try like this:
const Form2 = () => {
return (
<div className="card" id="form-card2">
<input
className="form-check-input"
type="checkbox"
value=""
id="options-check"
// onClick={Optionscheck}
/>
abcd
</div>
);
};
const Replica = () => {
const [replicaCount, setReplicaCount] = React.useState(0);
return (
<div>
<button
type="button"
className="btn btn-success"
onClick={() => setReplicaCount((prev) => prev + 1)}
>
Add
</button>
{Array.from({ length: replicaCount }).map((_, index) => (
<Form2 key={index}/>
))}
</div>
);
};
ReactDOM.render(<Replica />, 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>
Summary
You would have to create a handler for the replica button and a state that tracks how often the button was clicked, so that you are able to render as much form items as the button was clicked.
Example
import { useState } from "react";
import "./styles.css";
const FormItem = () => (
<div className="formItem">
<label>Check me</label>
<input type="checkbox" />
</div>
);
const ReplicaButton = ({ addFormItem }) => (
<button onClick={addFormItem}>Add more</button>
);
export default function Form() {
const [formCount, setFormCount] = useState(1);
const addFormItem = () => setFormCount(formCount + 1);
return (
<div>
<form className="formius">
{Array(formCount)
.fill(null)
.map(() => (
<FormItem />
))}
</form>
<ReplicaButton addFormItem={addFormItem} />
</div>
);
}

How to tigger onClick function of another component element

I created one class base component and one functional component. There are three buttons inside the functional component and I called that component to my class based component.
The functional component:
function PanelButton(props){
return (
<div>
<Button.Ripple
color="success"
type="submit"
style={{margin:"5px", width:"110px"}}
>
Submit
</Button.Ripple>
<Button.Ripple
color="primary"
id="clearButton"
type="button"
style={{margin:"5px", width:"110px"}}
>
Clear
</Button.Ripple>
<Button.Ripple color="danger" type="button" style={{margin:"5px", width:"110px"}}>
Close
</Button.Ripple>
</div>
)
}
export default PanelButton;
The class base component, in which I imported the functional component into:
import PanelButton from '../../components/customzied/PanelButton';
class TicketNew extends React.Component{
state = {
alertOption:[],
}
clickClear = () => {
console.log("ok");
}
render() {
const rqst = this.state.rquirdSate;
return (
<Card>
<Formik>
{ ({ errors, touched}) => (
<div>
<Form onSubmit={handleSubmit}>
<CardHeader>
<PanelButton />
</CardHeader>
<CardBody>
<Row />
</CardBody>
</Form>
</div>
)}
</Formik>
</Card>
)
}
}
export default TicketNew;
When I click the button(id = "clearButton") from functional component, I need to run the Click clear function in Class component.
You can pass onClick callback handlers as props to PanelButton to attach to each button's onClick prop. Pass clickClear as callback for clear button.
PanelButton
function PanelButton(props) {
return (
<div>
...
<Button.Ripple
color="primary"
id="clearButton"
type="button"
style={{ margin: "5px", width: "110px" }}
onClick={props.onClear} // <-- attach callback to button's onClick handler
>
Clear
</Button.Ripple>
...
</div>
);
}
TicketNew
class TicketNew extends React.Component {
state = {
alertOption: []
};
clickClear = () => {
console.log("ok");
};
render() {
const rqst = this.state.rquirdSate;
return (
<Card>
<Formik>
{({ errors, touched }) => (
<div>
<Form onSubmit={handleSubmit}>
<CardHeader>
<PanelButton onClear={this.clickClear}/> // <-- pass this.clickClear to onClear prop
</CardHeader>
<CardBody>
<Row></Row>
</CardBody>
</Form>
</div>
)}
</Formik>
</Card>
);
}
}
You can pass the clickClear function as props to the PanelButton component. The PanelButton code will look like the following,
function PanelButton(props){
return(
<div>
<Button.Ripple color="success" type="submit" style={{margin:"5px", width:"110px"}}>
Submit
</Button.Ripple>
<Button.Ripple color="primary" id="clearButton" onClick={props.onClickCallback} type="button" style={{margin:"5px", width:"110px"}}>
Clear
</Button.Ripple>
<Button.Ripple color="danger" type="button" style={{margin:"5px", width:"110px"}}>
Close
</Button.Ripple>
</div>
)
}
And the TicketNew code will look like this,
...
<CardHeader>
<PanelButton onClickCallback={this.clickClear.bind(this)} />
</CardHeader>
...

How to pass data from a table row and pass it to another component when it renders?

I have a component that shows a table and one of its columns have a field Actions which has buttons (view, edit, delete etc.). On button click, I need to render another component (component is a popup) and pass the data from the table so that it displays the data in some form which I need to further add.
I have managed to get the current data from its row by passing in onClick. I tried to use state for another component to render but it didn't work out. I'm using Semantic-UI React components to display the button with animations.
Here is the code that has the table,
const MainContent = () => {
const [actions, setActions] = useState(false);
const handleView = (rowData) => {
console.log(rowData);
setActions(true);
if (actions == true) return <ParentView />;
};
....
....
const contents = (item, index) => {
return item.routeChildEntry ? (
<>
<tr key={index}>
<td>{item.appName}</td>
<td></td>
<td>{item.createdTs}</td>
<td>{item.pattern}</td>
<td></td>
<td></td>
<td></td>
<td>
<Button animated onClick={() => handleView(item)}>
<Button.Content visible>View</Button.Content>
<Button.Content hidden>
<Icon name="eye" />
</Button.Content>
</Button>
</td>
</tr>
{item.routeChildEntry.map(routeContents)}
</>
) : (
....
....
....
);
};
return (
<div>
....
{loading ? (
<div className="table-responsive">
<table className="table">
<thead>
<tr>
<th>AppName</th>
<th>Parent_App</th>
<th>Created_Date</th>
<th>Req_Path</th>
<th>Resp_Code</th>
<th>Resp_Content_Type</th>
<th>Resp_Delay</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{data.map((routes, index) => {
return routes.map(contents, index);
})}
</tbody>
</table>
</div>
) : (
....
....
)}
</form>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default MainContent;
Below is the component to render on button click,
import React from "react";
import Popup from "reactjs-popup";
import { Icon } from "semantic-ui-react";
const Parent = (props) => {
return (
<Popup trigger={<Icon link name="eye" />} modal closeOnDocumentClick>
<h4>in parent</h4>
</Popup>
);
};
export default Parent;
How can I render the other component and pass data to it on button click?
Data can be passed to other components as props.
For example, if your component is <ParentView />, and the data you are passing is contained in the variable rowData, you can pass it as:
<ParentView dataPassedByAkhil = {rowData}/>
Then in your ParentView component,
export default function ParentView({dataPassedByAkhil}) {
console.log(dataPassedByAkhil);
Alternatively, you can accept the data as props as below
export default function ParentView(props) {
console.log(props.dataPassedByAkhil);
If you want to open and close another popup, you can pass a state just like above.
<PopupComponent open={stateSetForPopupByParent}/>
Example of popup using state.
Updated link above with how to pass data to the dialog from rows of buttons
Here is the full code:
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
const [valueofRow, setValueOfRow] = React.useState();
const handleClickOpen = (value) => {
setValueOfRow(value);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("John");
}}
>
Row 1 - value is John
</Button>
<br />
<br />
<Button
variant="outlined"
color="primary"
onClick={() => {
handleClickOpen("Sally");
}}
>
Row 2 Value is Sally
</Button>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="edit-apartment"
>
<DialogTitle id="edit-apartment">Edit</DialogTitle>
<DialogContent>
<DialogContentText>Dialog fired using state</DialogContentText>
<h1>{valueofRow} was clicked and passed from the row</h1>
<TextField
autoFocus
margin="dense"
id="field"
label="some field"
type="text"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="secondary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Submit
</Button>
</DialogActions>
</Dialog>
</div>
);
}

ReactJS - Access key of container div on click?

Here is the code that I'm working on right now.
How can I access the key that I have on the container div? Right now I'm just trying to console.log it but ultimately, I need to pass the key to an action so I can make a call to an API.
Thanks for any advice.
I want to access the key on the container div
renderRecipes() {
return _.map(this.props.recipes, recipe => {
return (
<div className="card" style={cardStyle} key={recipe.idMeal}>
<img className="card-img-top" src={recipe.strMealThumb} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{recipe.strMeal}</h5>
<button className="btn btn-outline-primary" onClick={this.viewRecipe}>
View Recipe Details
</button>
</div>
</div>
)
})
}
render() {
console.log(this.props.recipes);
return (
<div>
<h2>Main Ingredient Search Page</h2>
<SearchField />
<div className="d-flex flex-row flex-wrap">
{this.renderRecipes()}
</div>
</div>
);
}
}
You can do it pretty easily with an anonymous function:
<button className="btn btn-outline-primary" onClick={() => this.viewRecipe(recipe.mealId)}>
View Recipe Details
</button>
But the best way would be to extract the recipe into it's own component. Then it's nicely encapsulated and doesn't re-render onclick references.
class Recipe extends Component {
onViewDetails = () => {
this.props.onItemClick(this.props.id);
}
render() {
const {
name,
thumbnail
} = this.props;
return (
<div className="card" style={cardStyle}>
<img className="card-img-top" src={thumbnail} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{name}</h5>
<button className="btn btn-outline-primary" onClick={this.onViewDetails}>
View Recipe Details
</button>
</div>
</div>
)
}
}
--
return _.map(this.props.recipes, recipe => (
<Recipe
key={recipe.idMeal}
id={recipe.idMeal}
thumbnail={recipe.strMealThumb}
name={recipe.strMeal}
onItemClick={this.viewRecipe}
/>
);
I think you could do something like this
renderRecipes() {
return this.props.recipes.map(recipe => {
return (
<div className="card" style={cardStyle} key={recipe.idMeal}>
<img className="card-img-top" src={recipe.strMealThumb} alt="Recipe" />
<div className="card-body">
<h5 className="card-title">{recipe.strMeal}</h5>
<button className="btn btn-outline-primary" onClick={() => this.viewRecipe(recipe.idMeal)}>
View Recipe Details
</button>
</div>
</div>
)
})
}
Now, in the onClick function you'll receive the key!
I think you can define your viewRecipe method in this way:
viewRecipe = recipe => e => console.log(recipe)
viewRecipe will be a function that receives a recipe as parameter and returns another function which will be used for the onClick method:
<button className="btn btn-outline-primary" onClick={this.viewRecipe(recipe)}>
Or you can use also the techniques described in the docs which are the following:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Categories