Are props passed from parent components available only in render? - javascript

I'm struggling to understand where I can use props passed by parent's component. It seems that the props are available only in render() method.
The piece of code below is working perfectly but I can't easily serialize the form data and do "e.preventDefault()" thing (can I?)...it'd be better written in const Form = props => { ... })
class Form extends Component {
render() {
const {
handleSubmit
} = this.props;
return (
<div>
<form
onSubmit={this.props.handleSubmit.bind(this)}
>
<TextInput />
<button className="Button">Add</button>
</form>
</div>
);
}
}
BUT this does not work (props are not available in onSubmit method):
class Form extends Component {
onSubmit(e) {
e.preventDefault();
const data = ... serialized form data;
this.props.handleSubmit(data);
}
render() {
return (
<div>
<form
onSubmit={this.onSubmit}
>
<TextInput />
<button className="Button">Add</button>
</form>
</div>
);
}
}
Am I misunderstanding some react.js approach? Is there possibly some .bind(this) missing?
Thanks in advance.

Is there possibly some .bind(this) missing?
Yes you need/can use .bind, or use arrow functions, because now this does not refer to Form
class Form extends Component {
constructor() {
super();
this.onSubmit = this.onSubmit.bind(this)
}
...
}
or just use arrow function
<form
onSubmit={ (e) => this.onSubmit(e) }
>

Related

React JS validate form

Hello friends I'm pretty new to React JS so I want to ask you this:
I have a Parent and Child component. In Child component I have inputs (name,email etc) and in Parent component I have Button to save the input data in database.
My question is: How to validate inputs(i want them to be required) so the button can NOT call saveData function(to save in database) if the inputs are empty.
Here is Parent Component:
class Parent extends Component{
saveData = (e) => {
//some code
}
render() {
return (
<div>
<Child/>
<Button color="primary" onClick={this.saveData}>Submit</Button>
</div>
);
}
}
And here is Child Component:
class Child extends React.Component {
onInputChange = (e) => {
e.preventDefault();
this.props.onInputChange(e.target.name, e.target.value);
};
render() {
return (
<FormGroup>
<Input name="email" onChange={this.onInputChange}/>
</FormGroup>
);
}
}
I cant see the implementation of your onInputChange function but looks like its coming from parent component.
So, if you have onInputChange in your parent component then, you can have a disable state that is passed to your Button component and you need to set that disable state when onInputChange is called i.e
onInputChange = (name, value) => {
if(value === ''){
this.setState({disable: true});
}
else{
this.setState({
name: value;
disable:false
})
}
}
And pass it to your button i.e.
<Child />
<Button color="primary" disabled={disable} onClick={this.saveData}>

Why is my react form not working on codesandbox

I created a simple form here https://codesandbox.io/s/xenodochial-frog-7squw
It says You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue.
But there is an onChange handler being passed, so I don't understand. In addition the page reloads when I hit submit, even though preventDefault() is called
Thank you
The issue is this line:
const { str, handleChange, handleSubmit } = this.state;
handleChange and handleSubmit are not part of the state, but are instance methods, so you can pass them like so:
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
On line 25 you do:
const { str, handleChange, handleSubmit } = this.state;
Because of this, handleChange will be bound to this.state.handleChange which will be undefined as you have no property handleChange in your state.
You also forgot to pass the prop name to your Table-component.
I forked your code and updated it here: https://codesandbox.io/s/modest-meninsky-y1sgh
here is the correct Code for you:
import React from "react";
import "./styles/styles.css";
import Form from "./components/Form";
import Table from "./components/Table";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { str: "", desc: false };
console.log(4444);
this.handleChange = this.handleChange.bind(this); //<-- this binding
}
handleSubmit = event => {
event.preventDefault();
console.log("submitted");
};
handleChange = event => {
this.setState({ str: event.target.value });
};
render() {
const { str } = this.state; // <-- FIXED THIS
return (
<div className="App">
<Form str={str} onChange={this.handleChange} onSubmit={this.handleSubmit} />
<Table />
</div>
);
}
}
export default App;

Redux - How to get form values in its submit handler and call event.preventDefault()?

What I've been trying is to pass values from a form with Redux-Form to its handleSubmit with event.preventDefault(), so that submitting this form won't change URL.
Chances are that this is to do with react-router.
Here are excerpts of my attempt...
//form
class SampleForm extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<form onSubmit={this.props.handleSubmit}>
<Field name="body" component="textarea" />
<button type="submit" className="btn">Save</button>
</form>
</div>
);
}
}
//container...
class Container extends React.Component {
handleSubmit(event) {
event.preventDefault();
//How can I get the values from SampleForm?
}
render() {
return (
<div>
<SampleForm handleSubmit={this.handleSubmit}/>
</div>
);
}
}
I'm using react-router. Because of this, when I submit the form, the URL gets updated with the submitted values.
(When I was NOT using react-router, this didn't happen - I could simply get the values from handleSubmit().)
Any advice will be appreciated.
So you have your SampleForm component wrapped with Redux-Form. This decorated component should be passed an onSubmit prop from your Container which is the handler. You are passing handleSubmit() as a prop which is conflicting with redux-form's handleSubmit "middleware" that it is trying to do for you.
Change your Container component to pass "onSubmit" in in place of "handleSubmit" as follows:
//container...
class Container extends React.Component {
handleSubmit(event) {
event.preventDefault();
//How can I get the values from SampleForm?
}
render() {
return (
<div>
<SampleForm onSubmit={this.handleSubmit}/>
</div>
);
}
}
Now, your Container component should correctly receive the argument "values" as an argument and should be an object of form fields key/values. There is no need to call event.preventDefault() because redux-form's middleware (as I mentioned earlier) does that for you.
So instead of handleSubmit(event), change the event argument to "values" as below:
handleSubmit(values) {
console.log(values);
}

Passing props/state to/from parent component

So I have a parent component and a log in component.
I want the user to enter their details and then hit submit and then store/pass those details around so they can be used by other components.
how is this best done in React?
for example I have this input field inside my log in component
<p>
<input type="text" id="playerName" value={this.props.nameValue} onChange={this.props.handleNameChange}/>
</p>
Then I want to pass the value that is entered to the parent component
I have this function in my parent component:
handleNameChange(event){
this.setState({nameValue: event.target.value})
};
and in my return I have:
return (
<div>
<LoginPage handleClick={this.handleClick.bind(this)} handleNameChange={this.handleNameChange.bind(this)}/>
</div>
)
However, when I console.log(nameValue) I get undefined. any ideas? can add more code if necessary/relevant
From your example you never pass nameValue to the child component.
Updated your example of rendering the LoginPage, passing this.state.nameValue into the child component via props:
return (
<div>
<LoginPage
handleClick={this.handleClick.bind(this)}
handleNameChange={this.handleNameChange.bind(this)}
nameValue={this.state.nameValue}
/>
</div>
)
Your approach using state and props is fine. Are you sure that you shouldn't just be using...
console.log(this.state.nameValue);
This is a working example
class Parent extends React.Component {
constructor() {
super();
this.state = {
nameValue:''
};
}
render() {
return (
<Child handleClick={this.handleClick.bind(this)} handleNameChange={this.handleNameChange.bind(this)} nameValue={this.state.nameValue} />
);
}
handleNameChange(e) {
this.setState({
nameValue: e.target.value
});
}
handleClick() {
alert(this.state.nameValue);
}
}
class Child extends React.Component {
render() {
return (
<div>
<input type="text" value={this.props.nameValue} onChange={this.props.handleNameChange} />
<button onClick={this.props.handleClick}>Click Me!</button>
</div>
);
}
}
JSFiddle here.

why I can't get my onChange/onBlur handler work on custom component (reactjs)

Why I can't get my onChange handler work on child custom component? did I miss something. Can you guys help me with solutions, if there's best practice to do this can you tell me.
thanks.
Sample code:
var TextBox = React.createClass ({
getDefaultProps: function() {
return {
className: 'input-box'
};
},
render() {
return (
<input type="text" />
);
}
});
var Dashboard = React.createClass({
handleChange() {
alert('test');
}
render() {
return (
<div>
<h1>Components</h1>
<label>Input Box</label><br/>
<TextBox onBlur={this.handleChange} type="text" placeholder="hints (optional)"/>
</div>
)
}
});
//ReactDOM.render goes here...
You need to pass along the event handlers as props all the way to the input component. As it is, your input has no event bindings setup.
An easy way to ensure all of your props are getting passed down to the innermost child is to use the spread operator to pass all of your props in your TextBox component down to the child.
So, your TextBox component render function would look like:
render() {
return (
<input { ...this.props } type="text" />
);
}
And that's it! All the props you pass to <TextBox /> will make their way to the <input>
You need to use a callback to get the changes in parent component
try as below,
class TextBox extends React.Component {
render() {
return (
<input onBlur={this.props.callBack} type="text" />
);
}
}
class Dashboard extends React.Component {
render() {
const handleChange = () => {
console.log('---');
}
return (
<div>
<h1>Components</h1>
<label>Input Box</label><br/>
<TextBox callBack={handleChange} type="text" placeholder="hints (optional)"/>
</div>
);
}
}
React.render(
<Dashboard />,
document.getElementById('react_example')
);

Categories

Resources