React: document.getElementById (or onClick) does not work - reactjs

I want a random number to be generated and put into the "roomid" input field once the "generate" button is clicked, but the value shown is still 0 after I clicked the button. It guess it is not the problem of onClick because there was indeed a "?" added to the URL after I clicked the button. What is wrong with the code? Thank you so much for your help]1

React way of doing something like this would be
class StartStream extends Component {
state = { randomId: 0 }
generate = () => {
this.setState({ randomId: Math.random() * 1000 });
}
render() {
return <div>
<input type="text" value={this.state.randomId} />
<button onClick={this.generate}>Generate</button>
</div>;
}
}
Here is a working demo https://jsfiddle.net/tfc3javx/1/

Related

onChange function on checkbox isn't working | ReactJS

I'm learning ReactJS and today I can't resolve a difficulty, so I need your help.
I want to make a "Remember Me" for users that want to stay connected after reopening the website.
This is my code :
My function :
handleChangeCheckBox = (event) => {
console.log(event.target.checked)
this.setState({
isChecked: event.target.checked
})
}
When I call the function in the input checkbox field with an onChange :
<p>
<Input
type="checkbox"
name="rememberCheckbox"
className="rememberCheckbox"
id={this.state.isChecked}
onChange={this.handleChangeCheckBox}
/>
Remember Me
</p>
Nothing appears in my console when I click on the checkbox, so it seems like the calling function isn't working.
please try this. replace value with checked
<input type="checkbox"
name="rememberCheckbox"
checked={this.state.isChecked}
onChange={this.handleCheckBox}
/>
Code tested at given url
enter link description here
class App extends Component {
constructor(props) {
super(props);
this.state = { isChecked: false };
}
handleCheckBox = event => {
console.log(event.target.checked);
this.setState({
isChecked: event.target.checked
});
};
render() {
return (
<div>
<p>
<input
type="checkbox"
name="rememberCheckbox"
value={this.state.isChecked}
onChange={this.handleCheckBox}
/>
Remember Me
</p>
</div>
);
}
}
Welcome to Stack overflow!
Based on the code you shared, your function should be getting executed. I suspect you have an error somewhere else in your class rather than in those two code snippets you shared.
You can check this simple sandbox I made with a very barebones implementation like the one you have: https://codesandbox.io/s/react-simple-check-box-7etp4
One thing you're missing is using the checked html attribute rather than id. That's what will tell the checbox whether it's checked or not. It replaces the value attribute you use for input fields.
You also seem to be using an Input component. Try changing it for a normal HTML input instead.
it could be triggering twice.
if you are using create-react-app then your Appcomponent is wrapped in StrictMode like this:
<React.StrictMode>
<App />
</React.StrictMode>,
go to index.js and remove <React.StrictMode></React.StrictMode>
https://github.com/facebook/react/issues/12856#issuecomment-390206425
handleChangeCheckBox = () => { this.setState({ isChecked: ! this.state.isChecked }) }

google-maps-react infoWindow onChange issues

How to add a button in infowindow with google-maps-react?
Hello, I'm writing a React app, I was having an issue with changing state inside the InfoWindow from google-maps-react, the solution above helped me get through that hurdle.
Right now however, I'm having an issue with wanting to edit the content inside my InfoWindowEx component. Using the method above I am able to change the state of a text box inside the InfoWindowEx, however, when I click on the text box and I type it will let me type 1 letter and then I will have to click the text box again if I want to type the next letter, etc. I think this issue has to do with state.
I don't know if there is a solution to this, I have been trying a lot of different things, but hopefully someone can help me know what is going on.
Here is my InfoWindowEx component:
<InfoWindowEx
key={currentInfoWindow.id}
id={currentInfoWindow.id}
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
selectedPlace={this.state.selectedPlace}
onInfoWindowClose={this.onInfoWindowClose}
>
<div >
{infoWindowEditBoxes}
{infoWindowContent}
</div>
</InfoWindowEx>
the Edit boxes are rendering in conditional statements here are they:
if (this.state.editButton) {
infoWindowEditBoxes = (
<div>
<input key={this.props.marker} id="editedName" type="text" placeholder="New Bathroom Name" onChange={this.handleTextBoxState}></input>
<input key={this.props.marker} id="editedLocationName" type="text" placeholder="New Bathroom Location" onChange={this.handleTextBoxState}></input>
<button onClick={() => this.handleSubmitChangesButtonState()}>Submit Changes</button>
</div>
);
}
else {
infoWindowEditBoxes = null
}
and here is my state change function:
handleTextBoxState = (evt) => {
const stateToChange = {}
stateToChange[evt.target.id] = evt.target.value
this.setState(stateToChange)
console.log(stateToChange)
}
Thanks in advance!
I believe component state is getting updated properly in your example, apparently this behavior is related with InfoWindowEx component itself. The way how it is implemented, setState() causes to a re-render InfoWindow component which leads to losing input focus.
You could consider the following updated version of component which prevents re-rendering of info window if it has been already opened:
export default class InfoWindowEx extends Component {
constructor(props) {
super(props);
this.state = {
isOpen: false
};
this.infoWindowRef = React.createRef();
this.containerElement = document.createElement(`div`);
}
componentDidUpdate(prevProps) {
if (this.props.children !== prevProps.children) {
ReactDOM.render(
React.Children.only(this.props.children),
this.containerElement
);
this.infoWindowRef.current.infowindow.setContent(this.containerElement);
this.setState({
isOpen: true
});
}
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.isOpen) {
return this.props.marker.position.toString() !== nextProps.marker.position.toString();
}
return true;
}
infoWindowClose(){
this.setState({
isOpen: false
});
}
render() {
return <InfoWindow onClose={this.infoWindowClose.bind(this)} ref={this.infoWindowRef} {...this.props} />;
}
}
Demo

Attach ToggleClass events to future elements in ReactJS

I have multiple Div elements rendered dynamically through a loop.
Am trying to,
Attach an onClick event to the dynamically rendered elements.
Toggle the class through the onClick function.
The class name has to be toggled only to the span element that is clicked.
But the problem with the below code is, the class gets toggled to all the span elements rendered through this loop.
But I need to toggle the class only to the particular element that is clicked.
Though not the exact/complete code, the basic structure looks like this.,
constructor(props) {
super(props);
this.state = {
classnm: 'collapsed',
};
}
func2 = event => {
let currentClass = this.state.classnm;
if(currentClass == 'collapsed') {
this.setState({classnm: 'expanded'});
}
else {
this.setState({classnm: 'collapsed'});
}
};
render() {
return (
<div>
<Iterate>{this.renderIndexColumn}</Iterate>
</div>
);
}
// The below function gets called at least 10 times, rendering the below span element at least 10 times.
renderIndexColumn = () => {
return (
<div>
<span id={data.RefId} className = {this.state.classnm} onClick={(event) => {this.func2(event)}}>
<i className="material-icons">arrow_right</i></span>
</div>
);
};
If it is JQuery, I would have used ' on', 'this' to target the particular element & toggleClass.
Am not sure how to do the same in React.
Can someone help to achieve this? Thanks.
You don't need to set className to this.state.classnm. Just do this instead:
<span id={data.RefId} className = 'collapsed' ... />
And then your func2 should be something like:
func2 = event => {
event.target.classList.toggle('collapsed')
};

Show data on buttonclick

I am very new to react ,Trying to build a app . The basic functionality i am trying to implement is
I will have some text ,with a button called show details ,clicking the button will show details regarding the text .
I have the text as well as the details saved as a object array in state
Watcher_list :[
{
id:uuid.v4(),
name : "Memory",
showdetails : "False"
},
{
id:uuid.v4(),
name :"Network",
showdetails : "False"
}
]
for the component to render the page the code is as follows
class Watchers extends Component
{
showdetails(id)
{
this.props.showonclick(id);
}
render() {
if (this.props.item.showdetails ==="True") {
return (
<div className="Watchers" >
<li>{this.props.item.name}</li>
<p1>{this.props.item.id} </p1>
<button ref="show details" onClick={this.showdetails.bind(this,this.props.item.id)} >
Show Details
</button>
</div>
);}
else {
return (
<div className="Watchers" >
<li>{this.props.item.name}</li>
<button ref="show details" onClick={this.showdetails.bind(this,this.props.item.id)} >
Show Details
</button>
</div>
);
}
}
}
export default Watchers;
the handler for show click just updates the value of showdetails in the state ,ad upon re rendering the details are displayed.
I just wanted to know wether this is the best way to do this ,or is there a much smarter way that I can do the same thing ?
There are a couple of things that you can improve on,
First: you have a lot of redundant code that can be avoided by using conditional rendering like
class Watchers extends Component {
showdetails(id){
this.props.showonclick(id);
}
render() {
return (
<div className="Watchers" >
<li>{this.props.item.name}</li>
{this.props.item.showdetails ==="True" ? <p1>{this.props.item.id} </p1> : null }
<button ref={(ref) => this.showDetails = ref} onClick =
{this.showdetails.bind(this,this.props.item.id)} > Show Details </button>
</div>
);
}
}
export default Watchers;
Second: bind inside render is not a good pattern since it creates a new function everytime render is called. Check this answer on how to avoid it.
Third: I don't see any point on why you are using ref looking at the code in your question, but even if you need it, you need to use ref callback like ref={(ref) => this.showDetails = ref} instead of string refs since string refs are a legacy
You need not bind inside render function.
No need to set ref
For a change in ID, you do not require separate conditions. You can use the short circuit operator.
class Watchers extends Component {
constructor(props) {
super(props);
this.showdetails = this.showdetails.bind(this);
}
showdetails(id) {
this.props.showonclick(id);
}
render() {
return (
<div className = "Watchers">
<li> {this.props.item.name}</li>
{
this.props.item.showdetails === "True" &&
<p> {this.props.item.id} < /p>
}
<button onClick = {this.showdetails}>Show Details</button>
</div>
);
}
}
export default Watchers;
If you are setting state locally, you should probably set showDetails to Boolean true instead of a String like you have provided.

Simulate click - enzyme

I have a problem with Enzyme tool to test React app.
In my component I have login form and I want to test if after click on button the p tag will fill by text.
In fact after clicking submit there is sent request to the api (which doesn't exist now), the error about unreachable endpoint is returned.
Tried to test it in a lot of ways, but noticed one funny thing. Using:
it('returns error if endpoint not reachable', () => {
const wrapper = mount(<LoginForm dispatch={dispatch} store={store} />);
wrapper.find('button').simulate('click');
console.log(wrapper.debug());
});
returns HTML code in console. But there p tag is also not filled. So my question is how to use simulate function here?
First time I thought it is caused by some timeout. But using setTimeout gives the same result.
Thank you for your help!
Enzyme gives the ability to submit a click event. If it's not working i'm curious if you have the right element selected. An example from the docs...
https://github.com/airbnb/enzyme/blob/master/docs/api/ShallowWrapper/simulate.md#example
class Foo extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
const { count } = this.state;
return (
<div>
<div className={`clicks-${count}`}>
{count} clicks
</div>
<a href="url" onClick={() => { this.setState({ count: count + 1 }); }}>
Increment
</a>
</div>
);
}
}
const wrapper = shallow(<Foo />);
expect(wrapper.find('.clicks-0').length).to.equal(1);
wrapper.find('a').simulate('click');
expect(wrapper.find('.clicks-1').length).to.equal(1);
So in your particular case you mentioned an API call is made after clicking the submit button. You'll need to isolate and mock this behavior using something like Sinon.
http://sinonjs.org/

Resources