Reactjs Common state - javascript

I'm new to reactjs and I want an e-trade project. The problem is pressing the first "+" button, but increasing the number in the box next to it. How can I do this?
When I press the first, the other shouldn't increase because I will add more vegetable.
How can I solve this? Thank you so much
class App extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
};
}
increment() {
this.setState(prevState => ({
counter: this.state.counter + 1
}));
}
decrement() {
if (this.state.counter === 0) {
this.setState({
counter: 0
});
} else {
this.setState(prevState => ({
counter: this.state.counter - 1
}));
}
}
render() {
return (
<div class="container">
<div class="row" style={{ marginTop: '50px' }}>
<Card className="col-md-3" style={{ }}>
<Card.Img variant="top" src="https://res.cloudinary.com/sivadass/image/upload/v1493620046/dummy-products/broccoli.jpg" style={{ width: '200px',marginLeft:'30px' }}/>
<Card.Body>
<Card.Title style={{ textAlign: 'center' }}> Brocoli - 1
</Card.Title>
<Card.Text style={{ textAlign: 'center' }}>
1 $
</Card.Text>
<div style={{ textAlign: 'center' }}>
<Button onClick={this.decrement.bind(this)}>-</Button>
<h2 value="1">{this.state.counter}</h2>
<Button onClick={this.increment.bind(this)}>+</Button>
</div>
</Card.Body>
</Card>
<Card className="col-md-3" style={{ marginLeft:'10px' }}>
<Card.Img variant="top" src="https://res.cloudinary.com/sivadass/image/upload/v1493620046/dummy-products/broccoli.jpg" style={{ width: '200px',marginLeft:'30px' }}/>
<Card.Body>
<Card.Title style={{ textAlign: 'center' }}> Brocoli - 1
</Card.Title>
<Card.Text style={{ textAlign: 'center' }}>
1 $
</Card.Text>
<div style={{ textAlign: 'center' }}>
<Button onClick={this.decrement.bind(this)}>-</Button>
<h2 value="1">{this.state.counter}</h2>
<Button onClick={this.increment.bind(this)}>+</Button>
</div>
</Card.Body>
</Card>
</div>
</div>
)
}
}
export default App;

Can you please check whether you are looking for the following type of solution or not? Please ignore the styling I have just implemented the functionality.
constructor(props) {
super(props);
this.state = {
items:[{
name:"Veg 1",
counter:0
},{
name:"Veg 2",
counter:0
}]
};
}
increment = (index) =>{
let localItems = [...this.state.items];
localItems[index].counter += 1;
this.setState({
...this.state,
items:[...localItems]
})
}
decrement = (index) =>{
let localItems = [...this.state.items];
localItems[index].counter -= 1;
this.setState({
...this.state,
items:[...localItems]
})
}
render() {
const { classes } = this.props;
return (
this.state.items.length ? this.state.items.map((item,index)=>{
return (
<div>
<button onClick={()=>this.increment(index)}>+</button>
<span>{item.name} - {item.counter}</span>
<button onClick={()=>item.counter && this.decrement(index)}>-</button>
</div>
)
}):null
)
}

Related

How to pass data(count) from Quantity component to Mainpart component using lifting state up in react

Quantity component is my child class and Mainpart component is my parent class.i want to use my (count) in my parent class.but i dont know how to pass that data.sorry my english is not good.i think you will get the idea.
const MainPart = () => {
const submit = (event) => {
debugger;
event.preventDefault();
}
return (
<div>
<form onSubmit={submit}>
<Container>
<Row>
<Col sm={4}>
<Picture image='../images/test.jpg' alt='tent' />
</Col>
<Col sm={8}>
<Title title='4 Person tent' itemNo='Item No. MA000001' />
<Currency mark='$' price='150.00' />
<Quantity />
<div style={{ marginTop: '5%', textAlign: 'center' }}>
<input type='submit' value='ADD TO CART' style={{ backgroundColor: 'yellow', padding: '5px 5px 5px 5px' }} />
</div>
</Col>
</Row>
</Container>
</form>
</div>
);
};
--------------------------------------------------------------------------------------------------
const Quantity = (props) => {
const [count, setCount] = useState(0);
const increaseClick = () => {
setCount(count + 1 )
}
const decreaseClick = () => {
setCount(count - 1 )
}
return (
<>
<div style={{ display: 'flex', marginTop: '5%', marginLeft: '30%' }}>
<Button variant="primary" style={{ marginRight: '5%' }} onClick={decreaseClick}>-</Button>
<h3>{count}</h3>
<Button variant="primary" style={{ marginLeft: '5%' }} onClick={increaseClick}>+</Button>
</div>
</>
);
};
You have to create your state in parent and then pass to child, it will work.
const MainPart = () => {
const [count, setCount] = useState(0);
return (
...Your rest of code.
<Quantity count={count} setCount={setCount} />
)
}
Then In your child component, Use like this:
const Quantity = ({ count, setCount }) => {
const increaseClick = () => {
setCount(count + 1 )
}
const decreaseClick = () => {
setCount(count - 1 )
}
return (
<>
<div style={{ display: 'flex', marginTop: '5%', marginLeft: '30%'
}}>
<Button variant="primary" style={{ marginRight: '5%' }} onClick={decreaseClick}>-</Button>
<h3>{count}</h3>
<Button variant="primary" style={{ marginLeft: '5%' }} onClick={increaseClick}>+</Button>
</div>
</>
);
}

How to show/hide a button only in one object in an array of object?

I am using an array of objects to loop some services in my webpage. The data is
data.js
const data = [
{ type: "Mirror Cleaning", price: "29" },
{ type: "Ceiling Fan Cleaning", price: "39" },
{ type: "Window Cleaning", price: "139" },
{ type: "Toilet Seat Stain Removal", price: "109" },
{ type: "Wash Basin Cleaning", price: "49" },
{ type: "Exhaust Fan Cleaning", price: "79" },
{ type: "Kitchen Sink Cleaning", price: "79" },
{ type: "Gas Stove (HOB) Cleaning", price: "89" },
];
export default data;
I added a button in my app.js where I can select and unselect the data which I added to the service array. But the problem is whenever I select a service in my app all button name changed from Select to Unselect which I don't want. I want to achieve only the item that I clicked its button changed. But all the buttons in the window change. I know where is the problem but I don't know how to achieve what I want to. Here is the code of my app.js.
App.js
import "./styles.css";
import React from "react";
import data from "./data";
export default function App() {
const [service, setService] = React.useState([]);
const [display, setDisplay] = React.useState(true);
function Select(type, price) {
setService((prevItems) => [...prevItems, { type: type, price: price }]);
setDisplay(false);
}
function Unselect(type, price) {
setService((prevItems) => prevItems.filter((data) => data.type !== type));
setDisplay(true);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{data.map((data) => (
<>
<div key={data.type} style={{ height: "80px" }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
{display ? (
<button
onClick={() => Select(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Select
</button>
) : (
<button
onClick={() => Unselect(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Unselect
</button>
)}
</div>
</>
))}
<p> Selected Services comes here </p>
{service.map((data) => (
<>
<div
key={data.type}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
height: "50px"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
</>
))}
</div>
);
}
Here is the link of the codesandbox that I checked the code.
I want that only the particular service that is clicked its button change from select to unselect but all of them are changing.
please help.
There's a lot of redundant code; but thats alright, there's always room for improvement, but good that you attempted!
I've refactored your code with minimal code.
You can checkout the sandbox here.
What I've improved is:
Unnecessary use of multiple on change functions (select / unselect).
Unnecessary use of conditional rendering - I've merged it into one.
import './styles.css';
import React from 'react';
const data = [
{ type: 'Mirror Cleaning', price: '29' },
{ type: 'Ceiling Fan Cleaning', price: '39' },
{ type: 'Window Cleaning', price: '139' },
{ type: 'Toilet Seat Stain Removal', price: '109' },
{ type: 'Wash Basin Cleaning', price: '49' },
{ type: 'Exhaust Fan Cleaning', price: '79' },
{ type: 'Kitchen Sink Cleaning', price: '79' },
{ type: 'Gas Stove (HOB) Cleaning', price: '89' },
];
export default function App() {
const [selectedServices, setSelectedService] = React.useState([]);
function Select(type, price) {
// Check if selected service is already selected
if (!selectedServices.map((item) => item.type).includes(type)) {
// Add to array
data.find((eachItem) => eachItem.type === type).display = true;
setSelectedService((prevItems) => [...prevItems, { type: type, price: price }]);
} else {
// remove from array!
const allOtherServices = selectedServices.filter((item) => item.type !== type);
data.find((eachItem) => eachItem.type === type).display = false;
setSelectedService([...allOtherServices]);
}
}
// I want that only the particular service that is clicked its button change from selcet to unselect but all of them are changing
return (
<div className='App'>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{data.map((data) => (
<>
<div key={data.type} style={{ height: '80px' }}>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
<button
onClick={() => Select(data.type, data.price)}
style={{
color: 'white',
backgroundColor: 'black',
padding: '10px',
outline: '0',
border: 'none',
margin: '0px auto 0px 0px',
}}
>
{data.display ? 'Unselect' : 'Select'}
</button>
</div>
</>
))}
<p> Selected Services comes here </p>
{selectedServices.map((data) => (
<>
<div
key={data.type}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
height: '50px',
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
</>
))}
</div>
);
}
your display is always the same for all of your data item. If you want to select only 1 item at a time, you should define a typeToDisplay in your component's state to hold the type of the item you want to display. Then, conditionally display the item by comparing typeToDisplay with data.type
import "./styles.css";
import React from "react";
import data from "./data";
export default function App() {
const [service, setService] = React.useState([]);
const [typeToDisplay, setTypeToDisplay] = React.useState("");
function Select(type, price) {
setService((prevItems) => [...prevItems, { type: type, price: price }]);
setTypeToDisplay(type);
}
function Unselect(type, price) {
setService((prevItems) => prevItems.filter((data) => data.type !== type));
setTypeToDisplay("");
}
// I want that only the particular service that is clicked its button change from selcet to unselect but all of them are changing
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{data.map((data) => (
<>
<div key={data.type} style={{ height: "80px" }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
{typeToDisplay === data.type ? (
<button
onClick={() => Unselect(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Unselect
</button>
) : (
<button
onClick={() => Select(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Select
</button>
)}
</div>
</>
))}
<p> Selected Services comes here </p>
{service.map((data) => (
<>
<div
key={data.type}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
height: "50px"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
</>
))}
</div>
);
}
you can use index for this purpose as uniquely. Pass index to both select and unselect function index and then set this value to display and in rendering you again match display value with index. It will automatically work according to requirements as I have used your code for the same and it's working fine below.
import "./styles.css";
import React from "react";
import data from "./data";
export default function App() {
const [service, setService] = React.useState([]);
const [display, setDisplay] = React.useState('');
function Select(type, price, index) {
console.log(type, price, index);
setService((prevItems) => [...prevItems, { type: type, price: price }]);
setDisplay(index);
}
function Unselect(type, price, index) {
setService((prevItems) => prevItems.filter((data) => data.type !== type));
setDisplay(index);
}
// I want that only the particular service that is clicked its button change from selcet to unselect but all of them are changing
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{data.map((data, index) => (
<>
<div key={data.type + index} style={{ height: "80px" }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
{display === index ? (
<button
onClick={() => Select(data.type, data.price, index)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Select
</button>
) : (
<button
onClick={() => Unselect(data.type, data.price, index)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Unselect
</button>
)}
</div>
</>
))}
<p> Selected Services comes here </p>
{service.map((data) => (
<>
<div
key={data.type}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
height: "50px"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
</>
))}
</div>
);
}
Please let me know any queries. Thanks
What you are doing is using a single piece of state for different elements in your data array. You have to track it individually for every data item. I am going to demonstrate with code, as it is hard to explain and the answer will be very long. Please read the code comment to understand what you have to change.
import "./styles.css";
import React, { useEffect} from "react";
import data from "./data";
export default function App() {
// First create a new state based on your data by mapping through them individually
// and setting a new property name selected
const [dataState, setDataState] = React.useState(() => data.map(item => ({
...item,
selected: false
})));
const [service, setService] = React.useState([]);
function Select(type, price) {
setService((prevItems) => [...prevItems, { type: type, price: price }]);
// set that particular item's selected property to true when selected.
setDataState((st) => {
return st.map(item => {
if(item.type === type) {
return {
...item,
selected: true
}
}
return item
})
})
}
function Unselect(type, price) {
setService((prevItems) => prevItems.filter((data) => data.type !== type));
// similar for unselect, set the selected property to false
setDataState((st) => {
return st.map(item => {
if(item.type === type) {
return {
...item,
selected: false
}
}
return item
})
})
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{/* Now map through that dataState instead of data */ }
{dataState.map((data) => (
<>
<div key={data.type} style={{ height: "80px" }}>
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
{!data.selected ? (
<button
onClick={() => Select(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Select
</button>
) : (
<button
onClick={() => Unselect(data.type, data.price)}
style={{
color: "white",
backgroundColor: "black",
padding: "10px",
outline: "0",
border: "none",
margin: "0px auto 0px 0px"
}}
>
Unselect
</button>
)}
</div>
</>
))}
<p> Selected Services comes here </p>
{service.map((data) => (
<>
<div
key={data.type}
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
height: "50px"
}}
>
<div>{data.type}</div>
<div>{data.price}</div>
</div>
</>
))}
</div>
);
}
You can checkout the working example here.
Improvements:
Unnecessary use of multiple on change functions (select / unselect).
Unnecessary use of conditional rendering - I've merged it into one.
Unnecessary loops
const data = [
{ type: 'Mirror Cleaning', price: '29' },
{ type: 'Ceiling Fan Cleaning', price: '39' },
{ type: 'Window Cleaning', price: '139' },
{ type: 'Toilet Seat Stain Removal', price: '109' },
{ type: 'Wash Basin Cleaning', price: '49' },
{ type: 'Exhaust Fan Cleaning', price: '79' },
{ type: 'Kitchen Sink Cleaning', price: '79' },
{ type: 'Gas Stove (HOB) Cleaning', price: '89' },
];
export default function App() {
const [services, setServices] = React.useState([]);
function toggle(idx) {
let tmp = [...services];
data[idx].display = !data[idx].display;
tmp[idx] = tmp[idx] ? undefined : data[idx];
setServices(tmp);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{data.map(
(d, idx) =>
d && (
<>
<div key={d.type} style={{ height: '80px' }}>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<div>{d.type}</div>
<div>{d.price}</div>
</div>
<button
onClick={() => toggle(idx)}
style={{
color: 'white',
backgroundColor: 'black',
padding: '10px',
outline: '0',
border: 'none',
margin: '0px auto 0px 0px',
}}
>
{d.display ? 'UnSelect' : 'Select'}
</button>
</div>
</>
)
)}
<p> Selected Services comes here </p>
{services.map(
(service) =>
service && (
<>
<div
key={service.type}
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
height: '50px',
}}
>
<div>{service.type}</div>
<div>{service.price}</div>
</div>
</>
)
)}
</div>
);
}

onBlur and onChange Influence each other

const SimpleChoiceItem = (props: Props) => {
const { content, isSelected, onChange, onMove, onDelete, is_default } = props;
const [isEdit, setIsEdit] = React.useState<boolean>(false);
React.useEffect(() => {
if (!isSelected) {
setIsEdit(false)
}
}, [isSelected])
return <div style={{ margin: '17px 0' }}>
{
isEdit ? <div style={{ display: 'flex', justifyContent: 'space-between', }} onBlur={() => {
console.log('====onBlur===')
setIsEdit(false)
}}>
<div style={{ flex: 1 }}>
<Input value={content} onChange={e => onChange(e.target.value)} />
</div>
<div>
<Checkbox value={is_default} onChange={e => {
// When I click this element, I want to console the below words, But console the onBlur
console.log('===Check box === onChange==')
}}>默认</Checkbox>
<ArrowUpOutlined style={{ marginLeft: '20px', cursor: 'pointer' }} onMouseDown={() => onMove('up')} />
<ArrowDownOutlined style={{ marginLeft: '20px', cursor: 'pointer' }} onMouseDown={() => onMove('down')} />
<CloseOutlined style={{ marginLeft: '20px', cursor: 'pointer' }} onMouseDown={() => onDelete()} />
</div>
</div> : <div onClick={() => setIsEdit(true)}>{content}</div>
}
</div>
}
<CheckBox /> is Antd Component https://ant.design/components/checkbox-cn/
I want to click this check box, But console the onBlur and isEdit = false
Try to prevent default and stop propagation on checkbox to stop event triggering the other elements:
<Checkbox value={is_default} onChange={e => {
e.preventDefault();
e.stopPropagation();
console.log('===Check box === onChange==')
}}>默认</Checkbox>

Show length of an array based on what is left in array after its sliced

I have a react component that upon clicking showMore. it will load more comments. The issue im facing is that
View {showMore} More Comments
is not showing the items that are left in the array. Currently there are 7 comments in an array, and if you click show more, it will initially read show 3 more, but when i click again it says show 6 more. when it should be a lesser number than 6. It should be like show 2 more, etc. I'm quite confused on how to go about writing this logic.
What am i doing wrong
CommentList.tsx
import React, { Fragment, useState } from "react";
import Grid from "#material-ui/core/Grid";
import List from "#material-ui/core/List";
import Typography from "#material-ui/core/Typography";
import CommentItem from "./../commentItem/CommentItem";
import moment from "moment";
import OurLink from "../../../common/OurLink";
import OurSecondaryButton from "../../../common/OurSecondaryButton";
import OurModal from "../../../common/OurModal";
.....
function CommentList(props: any) {
const [showMore, setShowMore] = useState<Number>(3);
const [openModal, setOpenModal] = useState(false);
const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
const the_comments = props.comments.length;
const inc = showMore as any;
const showComments = (e) => {
e.preventDefault();
if (inc + 3 <= the_comments) {
setShowMore(inc + 3);
} else {
setShowMore(the_comments);
}
// setShowLessFlag(true);
};
........
const showMoreComments = () => {
return props.comments
.slice(0, showMore)
.sort((a, b) => a.id - b.id)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ cursor: "pointer", fontSize: "12px", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
</span>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
));
};
console.log(props.comments.slice(0, showMore).length);
return (
<Grid>
<Fragment>
<div style={{ margin: "30px 0px" }}>
<OurSecondaryButton onClick={(e) => showComments(e)} component="span" color="secondary">
View {showMore} More Comments
</OurSecondaryButton>
</div>
</Fragment>
{showLessFlag === true ? (
// will show most recent comments below
showMoreComments()
) : (
<Fragment>
{/* filter based on first comment */}
{props.comments
.filter((item, i) => item)
.sort((a, b) => b.id - a.id)
.slice(0, showMore)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ fontSize: "12px", cursor: "pointer", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</span>
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
))}
</Fragment>
)}
</Grid>
);
}
// prevents un-necesary re renders
export default React.memo(CommentList);
You want to show 3 more comments each time, or 1-2 items if there are less than 3 items left. So "View 3 More comments" if there are more than 3 left, or "View 1/2 More Comments" if there are only 1 or 2 left.
Or in other words cap the number of new comments shown at 3:
the minimum value of either 3 or (total number of comments - current shown comments = number of comments left).
View {Math.min(3, the_comments - inc)} More Comments

ReactJS In a user profile display only fields that have a value

Objective
Displaying only the fields that are filled in.
Background
In my application people will first fill out the application which has fields like "early reg fee, early reg date, regular reg fee, regular reg date" and so after they fill out all the information and click "view profile" they will see all the fields whether it's filled out or not.
If the value of one of the fields is null or undefined then it would not show up in the profile.
I was trying to do this and I started of by creating a state in the constructor "this.state {value: ''}"
class CompetitionProfileView extends React.Component {
constructor(props) {
super(props);
this.state {value: ''}
this.getContactCard = this.getContactCard.bind(this);
}
getCompetitionValue(path) {
const value = _.get(this.props.competition, path);
return value ? value : '';
}
getCompetitionDateValue(path) {
const value = _.get(this.props.competition, path);
return value ? value.toDateString() : '';
}
getCompetitionTimeValue(path) {
const value = _.get(this.props.competition, path);
return value ? `${
value.getHours() - 12
}:${value.getMinutes()}` : '';
}
getContactCard(num) {
return
this.getCompetitionValue(`Information.contactFirstName${num}`) ?
<Card key={num} style={{backgroundColor: '#f9f9f9', width: '32%'}} zDepth={2}>
<CardTitle title={`${this.getCompetitionValue(`Information.contactFirstName${num}`)} ${this.getCompetitionValue(`Information.contactFirstName${num}`)}`} subtitle={`${this.getCompetitionValue('Information.contactPosition1')}`} />
<Divider/>
<CardText>
<p style={{display: 'flex', justifyContent: 'center'}}><Phone/>{`${this.getCompetitionValue(`Information.contactFirstName${num}`)}`}</p>
<p style={{display: 'flex', justifyContent: 'center'}}><Email/>{`${this.getCompetitionValue(`Information.contactFirstName${num}`)}`}</p>
</CardText>
</Card>
:
'';
}
render(actions) {
return (
<div>
<div className="profileheader" style={{display: 'flex', flexDirection: 'column'}}>
<Paper className='banner-image' style={{backgroundImage: `url(${this.getCompetitionValue('Resources.boardPicture.url')})`,backgroundSize: 'cover',width: '100%', height: '200px', backgroundPositionY: '20%'}} zDepth={3}>
{/* <br style={{lineHeight: '15'}}/> */}
</Paper>
<Paper className='text-main' style={{textAlign: 'center'}}>
<label>{this.getCompetitionValue('Information.name')}</label>
</Paper>
<Paper className='logo-image' style={{backgroundImage: `url(${this.getCompetitionValue('Resources.competitionLogo.url')})`, backgroundSize: 'cover', width: '100px', height: '100px', marginTop: '-110px', marginLeft: '3%', paddingbottom: '20px'}} zDepth={3}/>
</div>
<hr/>
<div style={{display: 'flex', justifyContent: 'space-between'}}>
<Card style={{backgroundColor: '#f9f9f9', width: '49%'}} zDepth={2}>
<RaisedButton style={{display: 'flex', justifyContent: 'center'}} primary={true} label="Application Packet" onClick={() => window.open(this.getCompetitionValue('Resources.applicationPacket.url'), '_blank')}/>
</Card>
<Card style={{backgroundColor: '#f9f9f9', width: '49%'}} zDepth={2}>
<RaisedButton style={{display: 'flex', justifyContent: 'center'}} primary={true} label="Audition Video Info" onClick={() => window.open(this.getCompetitionValue('Resources.auditionVideoInfo.url'), '_blank')}/>
</Card>
</div>
<br/>
<div className='mainbody' style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between'}}>
<br/>
<div className='rightbody' style={{display: 'flex', flexDirection: 'column', width: '60%', flexWrap: 'wrap'}}>
<Card style={{backgroundColor: '#F0EFEF'}} zDepth={2}>
<CardHeader title="About Us" />
<Divider/>
<CardText>{`${this.getCompetitionValue('Information.compBlurb')}`}</CardText>
</Card>
<br/>
<Card style={{backgroundColor: '#F0EFEF'}} zDepth={2}>
<CardHeader title="Application Information" />
<Divider/>
<CardText>
<p><b>Early Reg:</b>{` ${this.getCompetitionDateValue('Information.dueDateEarly')}`}</p>
<p><b>Early Reg Fee:</b>{` ${this.getCompetitionValue('Information.earlyDues')}`}</p>
<p><b>Regular Reg:</b>{` ${this.getCompetitionDateValue('Information.dueDateRegular')}`}</p>
<p><b>Regular Reg Fee:</b>{` ${this.getCompetitionValue('Information.regularDues')}`}</p>
<p><b>Late Reg:</b>{` ${this.getCompetitionDateValue('Information.dueDateLate')}`}</p>
<p><b>Late Reg Fee:</b>{` ${this.getCompetitionValue('Information.lateDues')}`}</p>
<p><b>Applications Due At:</b>{` ${this.getCompetitionTimeValue('Information.dueTime')}`}</p>
<p><b>Time Zone:</b>{` ${this.getCompetitionValue('Information.timeZone')}`}</p>
<p><b>Penalties:</b>{` ${this.getCompetitionValue('Information.extraFees')}`}</p>
<p><b>Hear Back Date:</b>{` ${this.getCompetitionDateValue('Information.hearbackDate')}`}</p>
<p><b>Payment Method:</b>{` ${this.getCompetitionValue('Information.paymentMethods')}`}</p>
<br/>
</CardText>
</Card>
</div>
</div>
<br/>
<div className="contactinfo" style={{display: 'flex', justifyContent: 'space-around'}}>
{[1,2,3].map((num) => this.getContactCard(num))}
</div>
<br/>
{this.props.competition.Board.length > 0 &&
<Card style={{backgroundColor: '#F0EFEF'}} zDepth={2}>
<Table >
<TableHeader adjustForCheckbox={false} displaySelectAll={false}>
<TableRow>
{ Object.keys(this.props.competition.Board[0]).map((key) => <TableHeaderColumn key={key}>{key}</TableHeaderColumn>) }
</TableRow>
</TableHeader>
<TableBody displayRowCheckbox={false}>
{this.props.competition.Board.map((row, i) => (
<TableRow key={i}>
{ Object.keys(row).map((column) => <TableRowColumn key={column}>{row[column].name ? row[column].name : row[column]}</TableRowColumn>) }
</TableRow>
))
}
</TableBody>
</Table>
</Card>
}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
messages: state.messages
};
};
export default connect(mapStateToProps)(CompetitionProfileView);
You can use if statements in your render() function, like so:
render() {
if (this.props.thing1) {
return <h1>Thing 1</h1>
} else {
return (
<div className="warning">
<h2>Thing 2</h2>
</div>
)
}
}
You can even use functions in the render() function like this:
renderASmallPart() {
if (this.props.thing1) {
return <h1>Thing 1</h1>
} else {
return (
<div className="warning">
<h2>Thing 2</h2>
</div>
)
}
}
render() {
return (
<div>
<h1>My App</h1>
<h2>Here's a thing:</h2>
{this.renderASmallPart()}
</div>
)
}
You can use this to break up your large render() function into smaller functions that check what the value of their field is and only render something when the field has a non-empty value
You need to look into Conditional Rendering and only render that element when there is a value.
https://facebook.github.io/react/docs/conditional-rendering.html
https://atticuswhite.com/blog/render-if-conditionally-render-react-components/
http://devnacho.com/2016/02/15/different-ways-to-add-if-else-statements-in-JSX/
https://kylewbanks.com/blog/how-to-conditionally-render-a-component-in-react-native

Categories