I am working on react chat widget and in this I am able to get the count of new messages I am getting in badge but I want to clear the batch value once I click on the hidden button
export default class App extends React.Component
{
constructor(props)
{
state = {
count:0
}
}
}
for incrementing the value
this.setState((old_state)=>{
let new_count = ++old_state.count;
return { count: new_count }
})
inside render function badge={this.state.count}
and launcher component looks like this
const Launcher = ({ toggle, chatOpened, badge, bgcolor }) =>
<button type="button" style={{backgroundColor : bgcolor}} className={chatOpened ? 'rcw-launcher rcw-hide-sm' : 'rcw-launcher'} onClick={toggle}>
{chatOpened ?
<img src={close} className="rcw-close-launcher" alt="" />:
<React.Fragment><Badge badge={badge} /><img src={openLauncher} className="rcw-open-launcher" alt="" /></React.Fragment>
}
</button>;
I am not able to understand how can I cange the value after reading messages once.
When chatOpened is true, set state count to 0. Or pass 0 to badge count;
Related
I am using React v18.1, react-bootstrap v2.4. I have a Modal component I am trying to get to display upon a button press. The modal component is quite simple:
class AdjustmentModal extends React.Component {
constructor(props) {
super(props);
this.state = {
'show': this.props.show
};
this.handleClose = this.handleClose.bind(this);
}
handleClose() {
this.setState({ show: false })
}
render() {
return (
<Modal show={this.state.show} onHide={this.handleClose}>
[ ... Modal Content Here ... ]
</Modal>
);
}
}
export default AdjustmentModal;
As you can see, I bind the modal's show property to the value of show in state.
Then, in the component in which I want to display my modal, I have the following:
// Within render() ...
<AdjustmentModal
show={this.state.showAdjustment}
partNo={this.state.partNo}
onHandQty={this.state.onHandQty}
/>
// Futher on in the code, display the modal on click:
<Button className="icon" onClick={this.handleDisplayAdjustment}>
<i className="bi bi-pencil-square"></i>
</Button>
handleDisplayAdjustment :
handleDisplayAdjustment(event) {
event.preventDefault();
this.setState({
showAdjustment : true
});
}
Now, despite the value showAdjustment in the parent component changing to true, the modal doesn't display.
I could set the <Modal show={this.props.show} .../> instead, but props are read-only, so there is no way to close the modal again if reading from props rather than state.
You can use props, which is a better way to handle this if you want to close it then pass a method from the parent which when called update the state in the parent to false and due state update the parent component will re render and though the child component that is the modal component and the Modal will get the updated value which will be false. below is the code on how you can achieve that.
closeModal() {
this.setState({
showAdjustment: false
})
}
// Within render() ...
<AdjustmentModal
show={this.state.showAdjustment}
partNo={this.state.partNo}
onHandQty={this.state.onHandQty}
onClose={this.closeModal.bind(this)}
/>
// Futher on in the code, display the modal on click:
<Button className="icon" onClick={this.handleDisplayAdjustment}>
<i className="bi bi-pencil-square"></i>
</Button>
For the child component
class AdjustmentModal extends React.Component {
handleClose() {
this.props.onClose()
}
render() {
return (
<Modal show={this.props.show} onHide={this.handleClose}>
[ ... Modal Content Here ... ]
</Modal>
);
}
}
export default AdjustmentModal;
EDIT: Explaining the approach
This will make your Modal component a Controlled component that is controlled by Parent, also updating props as a state inside the child component is not the right way, which may create potential bugs.
I am trying to build a react page that shows a list of "messages subjects" received and when you click the down icon the messages relating to that subject appear directly below. (Imagine to help explain, when the user clicks the down icon on the line with 'Christmas' a white space needs to appear directly below and BEFORE the line with the 'New Year' text, so I can then display the message body, etc for each message relating to that subject.
Here is my code
import React from "react";
import "./Messages.css";
import { ReactComponent as DownIcon } from "../images/down-chevron.svg";
import Moment from 'moment';
class Messages extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
};
}
componentDidMount() {
this.setState({ isLoading: true });
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url =
"<my url>" +
this.props.location.state.userID;
fetch(proxyurl + url)
.then((res) => res.json())
.then((data) => this.setState({ data: data, isLoading: false }));
}
render() {
const { data, isLoading } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
if (data.length === 0) {
return <p> no data found</p>;
}
return (
<div>
<div className="messageSubjectHeader">
<div className="innerMS">Message Subject</div>
<div className="innerMS">Number of linked messages</div>
<div className="innerMS">Latest message Date and Time</div>
<div className="innerMS">View Messages</div>
</div>
{data.message_Subjects.map((ms) => (
<div className="messageSubject">
<div className="innerMS">{ms.subject}</div>
<div className="innerMS">{ms.message_Chain.length}</div>
<div className="innerMS">{this.getLatestMessageDateTime(ms.message_Chain)}</div>
<div className="innerMS">
<DownIcon className="innerMSDownIcon" />
</div>
</div>
))}
</div>
);
}
getLatestMessageDateTime(messageChain){
const lastmessage = messageChain.length -1;
Moment.locale('en');
var dt = messageChain[lastmessage].dateTime;
return(Moment(dt).format('ddd DD MMM YYYY hh:mm:ss'))
}
}
export default Messages;
You have to define the selected record id in the state and Update the selected id on the click of view messages button. And also add a Content Panel inside the loop and toggle the visibility based on the selected recorded Id in the state.
{data.message_Subjects.map((ms) => (
<>
<div className="messageSubject">
<div className="innerMS">{ms.subject}</div>
<div className="innerMS">{ms.message_Chain.length}</div>
<div className="innerMS">{"12/08/2020"}</div>
<div className="innerMS">
<button onClick={() => this.handleClick(ms.id)}>
{this.state.selectedId === ms.id ? "hide" : "Show"}
</button>
</div>
</div>
// show/hide the content based on the selection --> Content Panel
{this.state.selectedId === ms.id && (
<div className="content">{ms.description}</div>
)}
</>
))}
I have created a sample Demo - https://codesandbox.io/s/vigorous-hertz-x89p8?file=/src/App.js
Let me know if your use case is different.
You should have an onClick() handler if you want something to happen when user clicks an element, and then define handleOnClick() elsewhere in the component.
And you have no sub-component for the messages of a particular dated group, so, you'll need to code that, too.
Sub-Messages Component
I see that you have not defined any sub-components for messages. I don't know how your API works, so, I'll be general in that regard, but you'll want a <DateMessages/> component. This should have a constructor and render like...
constructor(props) {
super(props);
this.state = {'messages':[]};
}
render() {
return (
this.state.map((message) => {
return message.date + ' ' message.text;
});
);
}
Then, you'll need to populate this. So, add it as a ref in your <Messages/> component, as a child of <div className="messageSubject">. Since it starts out with no messages, it should come out as blank when appended to each date group. That'll look like datekey = ms.subject; <DateMessages ref={(instance) => {this.$datekey = instance}} />.
onClick Handler
So, your onClick handler would look like: <div className="messageSubject" onClick={(e, ms.subject) => this.handleOnClick(e, ms.subject)}>. You might have a handleOnClick() like...
handleOnClick(e, ms.subject) {
var datekey = ms.subject;
this.$datekey.setState(this is where an array of messages for datekey would be stored);
}
Advantages
Why do it this way? By having the state accurately reflect the data that the user is seeing, you'll be taking advantage of all the speedups of using ReactJS.
I've created a TabHeader which creates a Tab Menu. I want to show table contents based on months, and I've created a loop that runs through the current month and back to January. It is rendered correctly, but the content is changed out dynamically by the API based on the current URL. So, when I change the link/content, then the correct content is loaded, but the current marked Tab is still the first link. I'm using Material UI and would like to use the indicator that's packaged with the Tab component. I'm also coding in Typescript.
I've tried to do some Google searches, but can't seem to find someone with somewhat the same problem as I've got.
This is the TabHeader:
function TabHeader(props) {
const [value, setValue] = React.useState(0);
const { children, header, classes } = props;
function handleChange(event: React.ChangeEvent<{}>, newValue: number) {
setValue(newValue);
}
return (
// Removed for simplicity
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
variant="scrollable"
scrollButtons="auto"
>
{children}
</Tabs>
// Removed for simplicity
);
}
export default withStyles(styles)(TabHeader);
This is the Content Page. Here I've got the Months class which is the render object for my Tab:
class Months extends React.Component {
render() {
const { data } = this.props;
const months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
return (
<Tab
value={data+1}
label={months[new Date(0, 0).getMonth()+data]}
component={Link}
to={`/monthlyTable/${data+1}`}
/>
);
}
}
Then this is the main content that is render on the page:
class MonthlyTable extends React.Component {
state = {
monthlyTable: [],
isLoading: false,
}
componentDidMount() {
// Fetch content from API
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.monthId != this.props.match.params.monthId && this.state.isLoading != true) {
// Re-fetch content from API
}
}
render() {
const month = new Date().getMonth();
const rows = [];
for (var i = month; i >= 0; i--) {
rows.push(<Months key={i} data={i} />);
}
return (
// Removed for simplicity
<TabHeader header={this.state.monthlyTable.Title}>
{rows}
</TabHeader>
{this.state.isLoading ? '' : this.state.monthlyTable.Id && this.state.monthlyTable.Id.length > 0 && <ListTable data={this.state.monthlyTable.Id} />}
{this.state.isLoading ? '' : this.state.monthlyTable.Dates && this.state.monthlyTable.Dates.length > 0 && <ListTable data={this.state.monthlyTable.Dates} />}
// Removed for simplicity
);
}
}
It would be nice to mark the current Tab for user experience, so that you know what content is being showed.
put condition on window.location
if(window.location.pathname === "") then set style or className equal whatever you want to set.
for navbar example:
<ul class="navbar-nav">
<li class={window.location.pathname === "Home" : "nav-item active" ? "nav-item">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
</ul>
I am trying to change the background color of a page to one of three colors, each with a respective button. The buttons onClick function is supposed to call a function to change the color, but for some reason it is not working and instead the last button is setting the background color of the page when first loaded. Why is this? The below code is not working.
class Game extends React.Component
{
setBgColor(bgColor)
{
document.body.style.backgroundColor = bgColor;
}
render()
{
return(
<div id = "buttonWrapper">
<button id = "redButton" onClick = {this.setBgColor("red")}>RED</button>
<button id = "greenButton" onClick = {this.setBgColor("green")}>GREEN</button>
<button id = "blueButton" onClick = {this.setBgColor("blue")}>BLUE</button>
</div>
);
}
Thank you in advance.
#Mickael-conner, please use the following code for defining functions for your onClick events:
class Game extends React.Component
{
setBgColor(bgColor)
{
document.body.style.backgroundColor = bgColor;
}
render()
{
return(
<div id="buttonWrapper">
<button id="redButton" onClick={() => this.setBgColor("red")}>RED</button>
<button id="greenButton" onClick={() => this.setBgColor("green")}>GREEN</button>
<button id="blueButton" onClick={() => this.setBgColor("blue")}>BLUE</button>
</div>
);
}
The following article has explained different ways for defining functions inside React components:
5 Approaches for Handling this
I'm sure this is something trivial but I can't seem to figure out how to access the value of my button when the user clicks the button. When the page loads my list of buttons renders correctly with the unique values. When I click one of the buttons the function fires, however, the value returns undefined. Can someone show me what I'm doing wrong here?
Path: TestPage.jsx
import MyList from '../../components/MyList';
export default class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
console.log("button click", event.target.value);
}
render() {
return (
<div>
{this.props.lists.map((list) => (
<div key={list._id}>
<MyList
listCollection={list}
handleButtonClick={this.handleButtonClick}
/>
</div>
))}
</div>
);
}
}
Path: MyListComponent
const MyList = (props) => (
<div>
<Button onClick={props.handleButtonClick} value={props.listCollection._id}>{props.listCollection.title}</Button>
</div>
);
event.target.value is for getting values of HTML elements (like the content of an input box), not getting a React component's props. If would be easier if you just passed that value straight in:
handleButtonClick(value) {
console.log(value);
}
<Button onClick={() => props.handleButtonClick(props.listCollection._id)}>
{props.listCollection.title}
</Button>
It seems that you are not using the default button but instead some sort of customized component from another libray named Button.. if its a customezied component it wont work the same as the internatls might contain a button to render but when you are referencing the event you are doing it throug the Button component