Multiple call on same event - reactjs

I am calling two functions on the same event onChange
but the seconde one dosen't exucute this.updateValue
the value of the input doesn't change
----> but if we remove the first call and we change it to
---> onChange={this.updateValue}: the value on the input changes , it apear that there is a probleme while calling two function at once
import React from 'react'
class SearchBar extends React.Component
{
constructor(props)
{
super(props)
this.state = {input_value : ''}
}
updateValue = (event) =>
{
this.setState({input_value : event.target.value})
}
render()
{
return(
<React.Fragment>
<input
type="text"
value={this.state.input_value}
onChange={() => (this.props.toChild(this.state.input_value,this.updateValue))}
/>
</React.Fragment>
)
}
}
export default SearchBar

One function will be executed on onChange. You can do following
// prop to input in render
onChange={this.updateValue}
// In function
updateValue = (event) =>
{
this.props.toChild(event.target.value)
this.setState({input_value : event.target.value})
}

Related

I'm trying to make a Pomodoro timer for my first app. How can I start the session with updated state variables?

I declared 4 state variables in the parent component (App).
I have a function in the parent component (App) that lets me update these state variables. I passed this updateStudyTime function to my form child component (UpdateTimer).
I have another child component (StartSession) that is supposed to take the current state variables and start a log. I created a startStudySession function in the App parent. I passed this function as a prop to the child so it can run it.
The problem is that I think when it passes the function it takes the default state variables. So, even when I update the state parameters (study time or whatever) and it updates the App render, the StartSession child component has the function with the default variables.
Anyone got any ideas how to make sure the StartSession child component load the updated values?
Any general coding advice is also welcomed.
import './App.css';
import ReactDOM from "react-dom";
import React, { Component, useState } from 'react'
// Component to update time
class UpdateTimer extends React.Component {
constructor(props) {
super(props);
console.log(props);
// Take the passed function and make it a variable here
this.handleClick = this.props.updateStudytime;
console.log(this.handleClick);
// Form
// Declare States
this.state = {studytime: '',
shortbreaktime: '',
longbreaktime: ''};
// Handle Form Data
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
this.handleClick(this.state.studytime,this.state.shortbreaktime,this.state.longbreaktime);
event.preventDefault(); // Prevents refreshing the page
}
render(){
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Study Time:
<input name="studytime"
type="number" value={this.state.studytime} placeholder="25" onChange={this.handleChange} />
<br/>Short Break Time:
<input name="shortbreaktime"
type="number" value={this.state.shortbreaktime} placeholder="5" onChange={this.handleChange} />
<br/>Long Break Time:
<input name="longbreaktime"
type="number" value={this.state.longbreaktime} placeholder="15" onChange={this.handleChange} />
</label>
<br/>
<input type="submit" value="Update" />
</form>
</div>
);
}
}
class StartSession extends React.Component {
constructor(props) {
super(props);
console.log(props);
// Take the passed function and make it a variable here
//this.startStudysession = this.props.startStudysession.bind(this);
this.handleClick = this.props.startStudysession;
console.log(this.handleClick);
}
render() {
return (
<div>
{/* Call function in parent class that passes props */}
<button onClick={this.handleClick}>Start Session</button>
</div>
);
}
}
function App() {
// Declaring block times and session count
// The second variable is the call Function
const [studytime, setStudytime] = useState(25);
const [shortbreaktime, setShortbreaktime] = useState(5);
const [longbreaktime, setLongbreaktime] = useState(15);
const [blockcount, setBlockcount] = useState(0);
// Defining a function within parent component that can change parent state
function updateStudytime(studytime,shortbreaktime,longbreaktime) {
setStudytime(studytime);
setShortbreaktime(shortbreaktime);
setLongbreaktime(longbreaktime);
// Showing changes
console.log(studytime);
console.log(shortbreaktime);
console.log(longbreaktime);
}
// Defining a function that passes current state data for new pomodoro session
function startStudysession(){
// Send studytime, shortbreaktime, longbreaktime to the Clock function as a prop
console.log(studytime);
console.log(shortbreaktime);
console.log(longbreaktime);
console.log("it worked");
}
// DOM
return (
<div className="App">
<h1>Pomodoro</h1>
Study time: {studytime}<br/>
Short Break time: {shortbreaktime}<br/>
Long Break time: {longbreaktime}<br/><br/>
{/* Passing the function to the component as a prop */}
<UpdateTimer updateStudytime={updateStudytime} />
<StartSession startStudysession={startStudysession} />
</div>
);
}
export default App;

State Variable assigned to props data model undefined inside setState React

I have passed a data model as props from Parent Component (MinorStructures) to Child component (PhotoGallery).
The parent Component looks like the following:
export default class MinorStructures extends Component {
constructor(props)
{
super(props);
// This is a super data model class, its main function is to collect
// data from all the children components.
this.state = {
MinorStructures: {
layer: 3,
layerName: 'MinorStructures',
layerId: -1,
agencyId: -1, //to be determined later
galleryModel:{
selectedFile: null
}
}
};
this.panes = [
{
menuItem: 'Photo Gallery', render: () =>
<Tab.Pane>
<PhotoGallery triggerNeedSave={this.props.triggerNeedSave}
disabled={this.props.disabled}
loggedIn = {this.props.loggedin}
minorModel={this.state.MinorStructures}/>
</Tab.Pane>
},
];
}
}
I have removed few codes from the parent class which is not necessary for this problem.
The Child Component is like the following:
export default class PhotoGallery extends Component{
constructor(props) {
super(props)
const {minorModel} = this.props
this.state={
cameraOpen: false,
photoModel: minorModel.galleryModel
}
console.log("Constructor State ", this.state)
}
handleChange = e =>{
this.props.triggerNeedSave();
this.setState({[photoModel.selectedFile]:e.target.files[0]})
console.log(this.state)
}
render() {
const uploadClick = e => {
hiddenFileInput.current.click();
};
return (
<div>
{!this.state.cameraOpen && <Button size='tiny' onClick={uploadClick}
color='brown'
disabled ={this.props.disabled}>Upload Photos from Device</Button>}
<input id="photo" name="selectedFile" type="file"
onChange={this.handleChange}
ref={hiddenFileInput} style={{display:'none'}} />
<Button size='tiny' onClick={checkModel} color='brown'
disabled ={this.props.disabled}>
Click To Check
</Button>
</div>
);
};
return (
<div id="root">
<Gallery />
</div>
)}
}
In the state of PhotoGallery class I have a photoModel that takes the data model from MinorStructures as props. When I select a picture and do setState in the handleChange method of PhotoGallery class it says photoModel is not defined. But I have defined that variable in the state which stores data model passed as props from MinorStructures.
You are using dynamic keys when changing state with [] to access properties on this.state
this.setState({[photoModel.selectedFile]:e.target.files[0]})
The correct way would be to change state with
this.setState({photoModel.selectedFile:e.target.files[0]})
I set a name attribute for the file type input html tag and then used the below code to set the value
this.setState({ [name]: e.target.files[0] });

Moving props data to state to generate forms

I'm planning to add a prefilled form with React. I have the actual data on props. This is what I came up with.
#connect(...)
class Some extends React.Component {
state = {
...this.props.auth.user
}
render() {
// Create a form using the data on state
}
}
It looks not correct since I'm not using a react lifecycle hook here. I would like to ask if there is a better practice to achieve what I'm trying to do.
I am not sure about your architecture,since you are using uncontrolled component here, it is recommended to keep the source of truth at one place.
you can do something like this:
#connect(...)
class Some extends React.Component {
constructor(props) {
super(props);
this.state = {
userName:this.props.auth.user
}
}
handleChange = (event) => {
this.setState({userName: event.target.value});
}
render() {
return(
<div>
<input onChange={this.handleChange} id="some" type="text" value= {this.state.userName}/>
</div>
)
}
}
If you want to use controlled component that is controlled through parent/container. you can manage the values through props and set the props onChange.
So to elaborate on my previous responses you would do something like this to achieve what you want:
#connect(...)
class Some extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
}
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
render() {
return(
<div>
<input onChange={this.handleChange} id="some" type="text" value= {this.state.value|| this.props.value}/>
</div>
)
}
}
While your value is an empty string (in the state), the fields will be populated from your props and as soon as you start typing it will overwrite the prepopulated values with the ones in your state.
Best practices would be to actually have a Component that handles this logic and then passes the props to the form that should be just a dumb presentational component:
class SomeController extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
}
}
handleChange = (event) => {
this.setState({ value: event.target.value });
}
return (<Form handleChange={this.handleChange} value={this.state.value} />)
}
And then your form component:
const Form = (props) => (
<form>
<input onChange={props.handleChange} value={props.value} />
</form>
);
Hope this explanation helps.

Input in another component, error with target

Want to simplify my component, and want the search bar in another component to be more easy to read the code. And I have problems with target. I'm new in React...
export class SearchBar extends React.Component {
constructor(props) {
super(props)
this.handleUserInput = this.handleUserInput.bind(this)
}
render () {
return (
<input
className='SearchBar'
type='text'
placeholder='Search movies...'
onFocus={(e) => e.target.placeholder = ''}
onBlur={(e) => e.target.placeholder = 'Search movies...'}
onChange={()=>this.props.updateInput(this.handleUserInput())}
value={this.props.userInput}
/>
)
}
handleUserInput(e) {
return(e.target.value)
}
}
and the component where is it
<SearchBar value={this.state.userInput} updateInput={this.updateInput}/>
updateInput = (value) => {
this.setState({userInput:value})
}
Uncaught TypeError: Cannot read property 'target' of undefined
You haven't passed the event to your handleUserInput function.
onChange={()=>this.props.updateInput(this.handleUserInput())}
So e in the function is undefined. You need to change it to pass the event
onChange={(e)=>this.props.updateInput(this.handleUserInput(e))}

How to handle onChange event that sets the state in React?

I am learning React and in the below code I get ...cannot update during an existing state transition.... While looking to fix it, I read in SO that setState should not be used within render() as it calls render() repeatedly resulting in infinite loop. But I dont know how to fix it.
import React from 'react';
import ReactDOM from 'react-dom';
export default class CheckBox extends React.Component{
constructor() {
super();
this.state = {isChecked: false};
}
handleChecked () {
this.setState({isChecked: !this.state.isChecked});
}
render(){
var txt;
if (this.state.isChecked) {
txt = 'checked'
} else {
txt = 'unchecked'
}
return(
<div>
<input type="checkbox" onChange={this.handleChecked()}/>
<p>This box is {txt}</p>
</div>
);
}
}
ReactDOM.render(<CheckBox/>, document.getElementById('hello'));
You should pass to onChange reference to function but not call it., in your example you are calling handleChecked(because there is () after function) and result pass to onChange however result in this case will be undefined so onChange looks like onChange={ undefined }. Also, you can't set state during the initial render, but you are trying to do it with this.handleChecked() which contains this.setState.
export default class CheckBox extends React.Component{
constructor() {
super();
this.state = {isChecked: false};
// set this (with .bind),
// because you need get methods from CheckBox, like .setState
this.handleChecked = this.handleChecked.bind(this);
}
handleChecked () {
this.setState({isChecked: !this.state.isChecked});
}
render(){
var txt;
if (this.state.isChecked) {
txt = 'checked'
} else {
txt = 'unchecked'
}
// remove () after handleChecked because you need pass
// reference to function
// also add return statement before <div>
return <div>
<input type="checkbox" onChange={ this.handleChecked }/>
<p>This box is {txt}</p>
</div>
}
}
Example

Resources