onClick doesn't fire at all times - javascript

I started playing with some React/Redux + t7 (in order to avoid any sort of transpiling), for the sake of learning.
When it all started making some sense to me, I encountered this voodooish issue, where the bounded onClick function sometimes fires and sometimes doesn't (?!)
As you can see, clicking the plus button doesn't always invoke the bounded function to onClick.
I'm using the latest version of Google Chrome (v53).
What the hell?
JS
'use strict';
const store = Redux.createStore(Redux.combineReducers({
todos: (state = [], action) => {
switch(action.type) {
case 'ADD_TODO':
return state.concat([action.payload]);
default:
return [];
}
}
}));
t7.module((t7) => {
t7.assign("AddTodo", React.createClass({
addTodo() {
console.log('clicked');
return store.dispatch({
type: 'ADD_TODO',
payload: {
text: this.refs.todoText.value,
}
})
},
render() {
return t7`
<div className="row">
<div className="col-xs-4 form-group-lg">
<input className="form-control" ref="todoText"/>
</div>
<div className="col-xs-2">
<button className="btn btn-lg btn-info">
<span className="glyphicon glyphicon-plus"
onClick="${this.addTodo}"
style=${{fontSize: 'large'}}>
</span>
</button>
</div>
</div>
`;
}
}));
t7.assign("TodoList", React.createClass({
render() {
return t7`
<div className="row">
<div className="col-xs-12">
<ul>
${store.getState().todos.map((todo, i) => t7`
<li key=${i}>${todo.text}</li>
`)}
</ul>
</div>
<div>
`;
}
}));
const render = () => ReactDOM.render(
t7`
<div className="container">
<div className="jumbotron">
<h1>Todos</h1>
</div>
<AddTodo />
<TodoList />
</div>
`, document.getElementById('root')
);
store.subscribe(render);
render();
});

Your Click event works whenver your click on the glyphicon plus and not outside it. The issue is that you have placed the onClick event at the wrong place add it to the button rather than the span and it will work
render() {
return t7`
<div className="row">
<div className="col-xs-4 form-group-lg">
<input className="form-control" ref="todoText"/>
</div>
<div className="col-xs-2">
<button className="btn btn-lg btn-info" onClick="${this.addTodo}">
<span className="glyphicon glyphicon-plus"
style=${{fontSize: 'large'}}>
</span>
</button>
</div>
</div>
`;
}

Related

How can I increment/decrement separate counters in React?

I made a ticket order system for a project, however when I want to increment the amount of one of the tickets both of the counters increase. I am not sure why this happens, but I assume it is because only one value is stored in state.
export default function Ticket() {
const [count, setState] = useState(0); // useState returns a pair. 'count' is the current state. 'setCount' is a function we can use to update the state.
function increment(e) {
//setCount(prevCount => prevCount+=1);
setState(function (prevCount) {
return (prevCount += 1);
});
}
function decrement() {
setState(function (prevCount) {
if (prevCount > 0) {
return (prevCount -= 1);
} else {
return (prevCount = 0);
}
});
}
return (
<div>
<section className="ticket-step">
<h1>TICKETS</h1>
</section>
<div className="ticket-booking is-flexbox">
<section className="ticket-content">
<ul className="tickets-tab is-flexbox">
<li>Tickets</li>
<li>Abbonementen</li>
</ul>
<div className="ticket-list-section">
<div className="ticket-list-details heading">
<div id="calender">
<h3>Datum : 30 - 10 - 2022</h3>
</div>
<div id="opening">
<h3>Openingstijden: 12:00 - 20:00 </h3>
</div>
</div>
<div className="ticket-list-details">
<div className="ticket-block">
<div className="ticket-title">
<h3>Parkeer ticket</h3>
</div>
<div className="price">
<h3>Prijs: $20</h3>
</div>
<div className="counter">
<button className="increase-amount" onClick={increment}>+</button>
<input type="text" className="amount" defaultValue="0" value={count}/>
<button className="decrease-amount" onClick={decrement}>-</button>
</div>
</div>
<div className="ticket-block">
<div className="ticket-title">
<h3>Early Horror-ticket</h3>
</div>
<div className="price">
<h3>Prijs : $59</h3>
</div>
<div className="counter">
<button className="increase-amount" onClick={increment}>+</button>
<input type="text" className="amount" defaultValue="0" value={count}/>
<button className="decrease-amount" onClick={decrement}>-</button>
</div>
</div>
</div>
</div>
</section>
<aside className="sidebar-overview">
<h1>besteloverzicht</h1>
<div className="sidebar-overview-content">
</div>
<hr/>
<div className="sidebar-overview-total">
<h3>Totaal: $0</h3>
</div>
</aside>
</div>
</div>
)
}
I tried to change useState and somehow store different states of the counters in an array, but that didn't work.
How can use the counters separately and store the state of the different buttons?
I'd say create a Button component and use that instead of adding more counters... as you might want to re-use this in different pages later as well.
Button.js
import { useState } from "react";
function Button() {
const [count, setState] = useState(0); // useState returns a pair. 'count' is the current state. 'setCount' is a function we can use to update the state.
function increment(e) {
//setCount(prevCount => prevCount+=1);
setState(function (prevCount) {
return (prevCount += 1);
});
}
function decrement() {
setState(function (prevCount) {
if (prevCount > 0) {
return (prevCount -= 1);
} else {
return (prevCount = 0);
}
});
}
return (
<div className="counter">
<button className="increase-amount" onClick={increment}>
+
</button>
<input type="text" className="amount" defaultValue="0" value={count} />
<button className="decrease-amount" onClick={decrement}>
-
</button>
</div>
);
}
export default Button;
and just re-use it in your page;
export default function Ticket() {
return (
<div>
<section className="ticket-step">
<h1>TICKETS</h1>
</section>
<div className="ticket-booking is-flexbox">
<section className="ticket-content">
<ul className="tickets-tab is-flexbox">
<li>Tickets</li>
<li>Abbonementen</li>
</ul>
<div className="ticket-list-section">
<div className="ticket-list-details heading">
<div id="calender">
<h3>Datum : 30 - 10 - 2022</h3>
</div>
<div id="opening">
<h3>Openingstijden: 12:00 - 20:00 </h3>
</div>
</div>
<div className="ticket-list-details">
<div className="ticket-block">
<div className="ticket-title">
<h3>Parkeer ticket</h3>
</div>
<div className="price">
<h3>Prijs: $20</h3>
</div>
<Button/>
</div>
<div className="ticket-block">
<div className="ticket-title">
<h3>Early Horror-ticket</h3>
</div>
<div className="price">
<h3>Prijs : $59</h3>
</div>
<Button/>
</div>
</div>
</div>
</section>
<aside className="sidebar-overview">
<h1>besteloverzicht</h1>
<div className="sidebar-overview-content">
</div>
<hr/>
<div className="sidebar-overview-total">
<h3>Totaal: $0</h3>
</div>
</aside>
</div>
</div>
)
}
Hope this helps, see how I changed the value for the input tags and useState
Let me know if it worked
import React, { useState } from "react";
export default function App() {
const [count, setState] = useState({
first: 0,
second: 0
});
function increment(type) {
setState(prev => ({
...prev,
[type]: count[type] + 1
}))
}
function decrement(type) {
if(count[type] === 0) return;
setState(prev => ({
...prev,
[type]: count[type] - 1
}))
}
return (
<div>
<section className="ticket-step">
<h1>TICKETS</h1>
</section>
<div className="ticket-booking is-flexbox">
<section className="ticket-content">
<ul className="tickets-tab is-flexbox">
<li>Tickets</li>
<li>Abbonementen</li>
</ul>
<div className="ticket-list-section">
<div className="ticket-list-details heading">
<div id="calender">
<h3>Datum : 30 - 10 - 2022</h3>
</div>
<div id="opening">
<h3>Openingstijden: 12:00 - 20:00 </h3>
</div>
</div>
<div className="ticket-list-details">
<div className="ticket-block">
<div className="ticket-title">
<h3>Parkeer ticket</h3>
</div>
<div className="price">
<h3>Prijs: $20</h3>
</div>
<div className="counter">
<button className="increase-amount" onClick={() => increment("first")}>
+
</button>
<input
type="text"
className="amount"
defaultValue="0"
value={count.first}
/>
<button className="decrease-amount" onClick={() => decrement("first")}>
-
</button>
</div>
</div>
<div className="ticket-block">
<div className="ticket-title">
<h3>Early Horror-ticket</h3>
</div>
<div className="price">
<h3>Prijs : $59</h3>
</div>
<div className="counter">
<button className="increase-amount" onClick={() => increment("second")}>
+
</button>
<input
type="text"
className="amount"
defaultValue="0"
value={count.second}
/>
<button className="decrease-amount" onClick={() => decrement("second")}>
-
</button>
</div>
</div>
</div>
</div>
</section>
<aside className="sidebar-overview">
<h1>besteloverzicht</h1>
<div className="sidebar-overview-content"></div>
<hr />
<div className="sidebar-overview-total">
<h3>Totaal: $0</h3>
</div>
</aside>
</div>
</div>
);
}
You could implement a counter hook as well as a counter component.
useCounter.jsx
import { useState } from "react";
// An enum to track whether it's increment or decrement
const actionEnum = {
INCREMENT: "increment",
DECREMENT: "decerement"
};
const useCounter = (initialValue = 0) => {
// State to hold the value
const [count, setCount] = useState(initialValue);
// The function that set's the count based on the name of the element
function handleChange({ target }) {
const { name } = target;
setCount((prev) => (name === actionEnum.INCREMENT ? prev + 1 : prev - 1));
}
return {
count,
handleChange,
actionEnum
};
};
export default useCounter;
Counter.jsx
import useCounter from "./useCounter";
const Counter = () => {
const { count, handleChange, actionEnum } = useCounter();
return (
<>
<p>{count}</p>
<button name={actionEnum.INCREMENT} onClick={handleChange}>
+
</button>
<button name={actionEnum.DECREMENT} onClick={handleChange}>
-
</button>
</>
);
};
export default Counter;
Then finally just import the Counter component for each counter you need.
Example : https://codesandbox.io/s/patient-hooks-0ohyun?file=/src/App.js
You can also update the component so that it takes a prop for a fn that sets a global state which tracks all the counters
You should use 2 counters instead of just one, so you'll have 2 useState() statements.
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
Then your buttons and displays need to reference the separate counter states appropriately.
<div className="counter">
<button className="increase-amount" onClick={increment}>+</button>
<input type="text" className="amount" defaultValue="0" value={count1}/>
<button className="decrease-amount" onClick={decrement}>-</button>
</div>
You'll also need to have 2 separate increment functions and 2 separate decrement functions. Alternately, you can have one increment function that takes an argument to specify which counter to update.

Identify Clicked Button In Unordered List: React

I a week new in learning react coming from an angular background. I have the following unordered list in React.
const QueueManage: React.FC = () => {
const { queue, setQueue, loading, error } = useGetQueue();
const [btnState, setBtnState] = useState(state);
const enterIconLoading = (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
const item = '';
const btn = '';
console.log(item, btn);
setBtnState({ loading: true, iconLoading: true, item: item, btnType: btn });
};
<ul className="listCont">
{queue.map(queueItem => (
<li className="col-12" key={queueItem.id}>
<div className="row">
<div className="listName col-3">
<p>{queueItem.user.firstName} {queueItem.user.lastName}</p>
</div>
<div className="listName col-5">
<div className="row">
<div className="col-3">
<Button type="primary" loading={btnState.loading} onClick={enterIconLoading}>
Assign
</Button>
</div>
<div className="col-3">
<Button type="primary" loading={btnState.loading} onClick={enterIconLoading}>
Absent
</Button>
</div>
<div className="col-3">
<Button type="primary" loading={btnState.loading} onClick={enterIconLoading}>
Done
</Button>
</div>
<div className="col-3">
<Button type="primary" loading={btnState.loading} onClick={enterIconLoading}>
Cancel
</Button>
</div>
</div>
</div>
</div>
</li>
)
)}
</ul>
}
For each list item, the list item will have for buttons, namely Assign, Absent, Done, Cancel. My goal is to identify which button was clicked and for which list item so that I can apply a loader for that specific button. Can any one please assist me with an explanation of how I can achieve this in my code
Here is a visual representation of the list that i get
https://i.imgur.com/kxcpxOo.png
At the moment went i click one button, all buttons are applied a spinner like below:
Your assistance and explanation is highly appreciated.
The Reactful approach involved splitting the li into a separate component. This will help keep each item's state separate. Let's call that QueueItem.
const QueueItem = ({ user }) => {
const [loading, setLoading] = useState(false)
function onClickAssign() {
setLoading(true)
// do something
setLoading(false)
}
function onClickAbsent() {
setLoading(true)
// do something
setLoading(false)
}
function onClickDone() {
setLoading(true)
// do something
setLoading(false)
}
function onClickCancel() {
setLoading(true)
// do something
setLoading(false)
}
return (
<li className='col-12'>
<div className='row'>
<div className='listName col-3'>
<p>
{user.firstName} {user.lastName}
</p>
</div>
<div className='listName col-5'>
<div className='row'>
<div className='col-3'>
<Button type='primary' loading={loading} onClick={onClickAssign}>
Assign
</Button>
</div>
<div className='col-3'>
<Button type='primary' loading={loading} onClick={onClickAbsent}>
Absent
</Button>
</div>
<div className='col-3'>
<Button type='primary' loading={loading} onClick={onClickDone}>
Done
</Button>
</div>
<div className='col-3'>
<Button type='primary' loading={loading} onClick={onClickCancel}>
Cancel
</Button>
</div>
</div>
</div>
</div>
</li>
)
}
Here I've also split out each button's onClick into a separate callback since they are well defined and probably have unique behaviours. Another approach mentioned above in a comment is
function onClickButton(action) {
...
}
<Button type='primary' loading={loading} onClick={() => onClickButton('cancel')}>
Cancel
</Button>
This follows the action / reducer pattern which might be applicable here instead of state (useState)
Move the buttons or the whole li to a component and let each list manage it's state.
// Get a hook function
const {useState} = React;
//pass the index of li as prop
const Buttons = ({ listId }) => {
const [clicked, setClickedButton] = useState(0);
return (
<div>
<button
className={clicked === 1 && "Button"}
onClick={() => setClickedButton(1)}
>
Assign
</button>
<button className={clicked === 2 && "Button"} onClick={() => setClickedButton(2)}>Absent</button>
<button className={clicked === 3 && "Button"} onClick={() => setClickedButton(3)}>Done</button>
<button className={clicked === 4 && "Button"} onClick={() => setClickedButton(4)}>Cancel</button>
</div>
);
};
// Render it
ReactDOM.render(
<Buttons />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<style>
.Button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
</style>
<div id="react"></div>
In addition to the previous answer it's worth adding that making simple components (in our case buttons) stateful is often considered a bad practice as it gets harder to track all the state changes, and to use state from different buttons together (e.g. if you want to disable all 4 buttons in a row after any of them is pressed)
Take a look at the following implementation, where entire buttons state is contained within parent component
enum ButtonType {
ASSIGN, ABSENT, DONE, CANCEL
}
// this component is stateless and will render a button
const ActionButton = ({ label, loading, onClick }) =>
<Button type="primary" loading={loading} onClick={onClick}>
{label}
</Button>
/* inside the QueueManage component */
const [buttonsState, setButtonsState] = useState({})
const updateButton = (itemId: string, buttonType: ButtonType) => {
setButtonsState({
...buttonsState,
[itemId]: {
...(buttonsState[itemId] || {}),
[buttonType]: {
...(buttonsState[itemId]?.[buttonType] || {}),
loading: true,
}
}
})
}
const isButtonLoading = (itemId: string, buttonType: ButtonType) => {
return buttonsState[itemId]?.[buttonType]?.loading
}
return (
<ul className="listCont">
{queue.map(queueItem => (
<li className="col-12" key={queueItem.id}>
<div className="row">
<div className="listName col-3">
<p>{queueItem.user.firstName} {queueItem.user.lastName}</p>
</div>
<div className="listName col-5">
<div className="row">
<div className="col-3">
<ActionButton
label={'Assign'}
onClick={() => updateButton(queueItem.id, ButtonType.ASSIGN)}
loading={isButtonLoading(queueItem.id, ButtonType.ASSIGN)}
/>
</div>
<div className="col-3">
<ActionButton
label={'Absent'}
onClick={() => updateButton(queueItem.id, ButtonType.ABSENT)}
loading={isButtonLoading(queueItem.id, ButtonType.ABSENT)}
/>
</div>
<div className="col-3">
<ActionButton
label={'Done'}
onClick={() => updateButton(queueItem.id, ButtonType.DONE)}
loading={isButtonLoading(queueItem.id, ButtonType.DONE)}
/>
</div>
<div className="col-3">
<ActionButton
label={'Cancel'}
onClick={() => updateButton(queueItem.id, ButtonType.CANCEL)}
loading={isButtonLoading(queueItem.id, ButtonType.CANCEL)}
/>
</div>
</div>
</div>
</div>
</li>
)
)}
</ul>
)
The goal here is to keep buttons loading state in parent component and manage it from here. buttonsState is a multilevel object like
{
'23': {
[ButtonType.ASSIGN]: { loading: false },
[ButtonType.ABSENT]: { loading: false },
[ButtonType.DONE]: { loading: false },
[ButtonType.CANCEL]: { loading: false },
},
...
}
where keys are ids of queueItems and values describe the state of the 4 buttons for that item. It is usually preferred to use useReducer instead of nested spreading in updateButton but it is good to start with

Modal Window not detect well I click on the Login or Sign up button

When clicked close button code detects in the console that the component want's to be hidden but when I want to open the modal window by clicking the Logic or Signup button in navigation.js file those buttons don't detect any activity to the console.
This where I'm got the tutorial on how to do the modal widow but tried to work out for my need's --> https://alligator.io/react/modal-component/
Modal Window Component:
import React from 'react';
const Modal = ({ show, children }) => {
const showHideClassName = show ? 'modal display-block' : 'modal display-none';
return (
<div className={showHideClassName}>
<section className='modal-main'>
{children}
</section>
</div>
);
};
class App extends React.Component {
state = { show: false }
showSignup = () => {
this.setState({ show: true });
console.log('I was triggered during componentDidMount')
}
showLogin = () => {
this.setState({ show: true });
console.log('Fuck this not show the login form')
}
hideModal = () => {
this.setState({ show: false });
console.log('Yeah its hide the login and signup form')
}
render() {
return (
<div>
<Modal show={this.state.show} handleclose={this.hideModal} >
<div className="blkOverlay">
{/* This is Login Form to log in to your profile */ }
<div className="formContent modal-main">
<button className="closebtn" onClick={this.hideModal}>Close </button>
<h2>Welcome Back <span>Brandon!</span></h2>
<form data-show={this.state.show.toString()}>
<input type="text" name="email" placeholder="Email Address" />
<input name="password" type="text" placeholder="Password" />
<div className="passContent">
<div className="checkingPass">
<input className="inline" type="checkbox" name="check" value="Remember Password"/>
<span className="inline">Remember Password</span>
</div>
<p className="passFont">Forgot Password</p>
</div>
<input className="formmbtn" type="button" name="button" value="Login"/>
<div className="social-media-button">
<input className="clearbtn" type="button" name="button" value="Sign in with Facebook"/>
<div className="divider"/>
<input className="clearbtn" type="button" name="button" value="Sign in with Facebook"/>
</div>
<p className="passFont">Don't have an account? <span>Sign up</span></p>
</form>
</div>
{/* This is Sign up to create a account */}
</div>
</Modal>
</div>
)
}
}
export default App;
Navigation Component (Where the buttons are at to call the modal window to appear on click)
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import Dropdown from "../components//pages/dropdowns/dropdowns.js";
import "../components/pages/SignupModal/signupmodal.js";
import hamburger from "../images/menu.svg";
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
e.preventDefault();
this.setState(prevState => ({
isExpanded: !prevState.isExpanded, // negate the previous expanded state
}));
}
render() {
const { isExpanded } = this.state;
return (
<Router>
<div className="NavbarContainer">
<div className="mobilecontainer LeftNav">
<h2 className="BrandName LeftNav mobileboxmenu inline FarRight">Kommonplaces</h2>
<div className="hamburger inlinev" >
<img
onClick={e => this.handleToggle(e)}
alt="menubtn"
src={hamburger}
/>
</div>
</div>
<ul className={`NavBar collapsed ${isExpanded ? "is-expanded" : ""}`}>
<Dropdown/>
<li className="RightNav"><Link to="/">Host Your Space</Link></li>
<li className="RightNav"><Link to="/">About Us</Link></li>
<li className="RightNav"><Link to="/">Contact Us</Link></li>
<div className="btnflexright">
<button className="RightNav"><Link onClick={ this.showSignup } to="/">Sign Up</Link></button>
<button className="RightNav"><Link onClick={ this.showLogin } to="/">Login</Link></button>
</div>
</ul>
</div>
</Router>
);
}
}
export default Navigation;
Any, helpful tips and advice would help, please.
That's because you placed the onClick event in the Link rather than on the button component. Change to the code below:
<div className="btnflexright">
<button className="RightNav" onClick={ this.showSignup }>
<Link to="/">Sign Up</Link>
</button>
<button className="RightNav" onClick={ this.showLogin }>
<Link to="/">Login</Link>
</button>
</div>

reload or re render react child component

i got trouble making a search function in react, not the function itself but how it redirecting. before i've tried using redirect and it doesn't load the parent component. no solution, then i changes the logic using Link to instead of redirect to. now the problem is the child component doesnt re-render and the only thing changes is the url.
Here is the complete code.
Child component:
class Search extends Component {
state = {
products: [],
count: '',
}
componentDidMount() {
window.scrollTo(0, 0)
const { match: { params } } = this.props;
axios.get('http://localhost:8000/api/v1/cari/' + params.userId)
.then(response => {
this.setState({ products: response.data.data, count: response.data.jumlah });
})
}
componentWillReceiveProps(props) {
this.forceUpdate();
this.setState({ diCari: this.state.diCari });
}
render() {
var jumlah = <div className="judul cari">Menampilkan {this.state.count} Produk</div>;
var { products } = this.state;
var hasil = products.map(products => {
<div className="kotakproduk produkcari" />
})
return (
<div>
<div className="gambarproduk">
<img src="https://www.mobiledokan.co/wp-content/uploads/2019/09/Xiaomi-Mi-9-Pro-Dream-White.jpg" />
</div>
<div className="nama">
{products.merk} {products.tipe}
</div>
<div className="harga">
<NumberFormat value={products.harga} displayType={'text'} thousandSeparator={true} prefix={'Rp. '} />
</div>
</div>
)
}
}
Parent component
class Master extends Component {
state = {
cari: '',
diCari: false
};
handleChange1 = (e) => {
this.setState({
cari: e.target.value
})
}
render() {
return (
<div>
<div className="header">
<Link to="/home">
<div className="logo">
<img src="/img/tokopon2.png" />
</div>
</Link>
<input type="text" name="search" placeholder="Search.." onChange={this.handleChange1} />
<Link to={"/search/" + this.state.cari}><button type="submit"><i className="fa fa-search"></i></button></Link>
<div className="login-button">
<Link to="/login">Login</Link>
<div className="keranjang-mobile">
<a href="#">
<span className="glyphicon glyphicon-shopping-cart"></span>
</a>
</div>
<div className="keranjang">
<a href="#" className="btn btn-info btn-lg">
<span className="glyphicon glyphicon-shopping-cart"></span> Keranjang Belanja
</a>
</div>
</div>
</div>
</div>
)
}
}
i already tried history.push still no changes

Adding comment using react and node

I'm trying to build a website where users can comment on a given post. i want to display comment when Button is pressed. All work fine, but i want to show/hide comment when i click comment button. I'm using comment button inside map function so all the elements are executing it. how to show/hide comment for individual element? Please Help.
render() {
return (
<div className="container">
{this.state.queries.map((item, key) => {
return (
<div key={key}>
<hr />
<div className="list-group-item list-group-item-secondary row ">
<div className="authorName">{item.name}</div>
<div>{item.description}</div>
<hr />
<div>
<button
className="btn btn-info"
data-toggle="collapse"
data-target="#demo"
onClick={() => {
return fetch("/queries/" + item._id)
.then(Response => Response.json())
.then(data => {
this.setState({ comment: data.comments });
});
}}
>
Comment
</button>
<div id="demo" className="collapse">
<br />
<form
className="commentForm"
action={"http://localhost:5000/queries/" + item._id}
method="POST"
>
<input
type="text"
className="form-control"
placeholder="Write a comment..."
name="comment"
/>
<button className="btn btn-lg btn-primary btn-block">
Post
</button>
</form>
<br />
<div>
{this.state.comment.map((commentItem, key) => {
return (
<div className="list-group-item list-group-item-success">
<span className="authorName">
{commentItem.author}
</span>
{commentItem.text}
</div>
);
})}
</div>
</div>
</div>
</div>
</div>
);
})}
</div>
);
}
JSONfrom server at 'localhost:5000/queries/'+item._id
{
"comments": [
{
"_id": "5b5eadeeb415381598bdc825",
"text": "sfsdfsd",
"__v": 0
},
{
"_id": "5b5ecbe5b415381598bdc827",
"text": "hii from alex",
"__v": 0
},
{
"_id": "5b5ecd9ed8f72736c830a311",
"text": "asdad",
"__v": 0
}
],
"_id": "5b5ea97f7fb6e02d58b80dba",
"name": "ram#gmail.com",
"description": "Is axios still in use?",
"__v": 3
}
First, I would highly recommend reading the Thinking in React part of react documentation. You are facing these problems because you are not leveraging/using the power of encapsulation that React components bring.
Root Cause: You have multiple places where you can show comments, however you are maintaining them in a single state, so one will always override for others.
From looking at your code, it looks like you may be aiming for the following structure:
Container -
- Posts
- Comments
Container would be responsible for showing all the "posts" --> this.state.queries.map functionality.
Each Post can be responsible for rendering its own comments. That way, even if you have multiple posts, each is responsible for their own comment section.
So your post component can look like:
class Post extends React.Component{
state = {
comments: []
}
render() {
let {item, key} = this.props;
return (<div key={key}>
<hr />
<div className="list-group-item list-group-item-secondary row ">
<div className="authorName">{item.name}</div>
<div>{item.description}</div>
<hr />
<div>
<button
className="btn btn-info"
data-toggle="collapse"
data-target="#demo"
onClick={() => {
return fetch("/queries/" + item._id)
.then(Response => Response.json())
.then(data => {
this.setState({ comment: data.comments });
});
}}
>
Comment
</button>
<div id="demo" className="collapse">
<br />
<form
className="commentForm"
action={"http://localhost:5000/queries/" + item._id}
method="POST"
>
<input
type="text"
className="form-control"
placeholder="Write a comment..."
name="comment"
/>
<button className="btn btn-lg btn-primary btn-block">
Post
</button>
</form>
<br />
<div>
{this.state.comment.map((commentItem, key) => {
return (
<div className="list-group-item list-group-item-success">
<span className="authorName">
{commentItem.author}
</span>
{commentItem.text}
</div>
);
})}
</div>
</div>
</div>
</div>
</div>)
}
And your Container can be:
render() {
return (
<div className="container">
{this.state.queries.map((item, key) => {
return (<Post item={item} key={key} />)

Categories

Resources