React render props.children fails when run children events (children are components) - reactjs

I'm creating a ReactJS package. I've created a component called Form which contains a normal form. When calling it on the App.js I add components on it which called TextField. So, the code on App.js is:
import React, { Component } from 'react'
import { Form, TextField } from 'form2'
import './App.css'
export default class App extends Component {
render () {
return (
<div>
<Form>
<TextField placeholder="Type your name..." />
<TextField placeholder="Type your email..." />
</Form>
</div>
)
}
}
And the code of the Form component is:
import React, { Component } from 'react'
class Form extends Component {
constructor(props) {
super(props)
this.state = {
values: {}
}
}
renderChildren = () => {
return this.props.children;
};
render() {
return <form>
{ this.renderChildren() }
</form>
}
}
export default Form
And this is mt TextField component:
import React, { Component } from 'react'
class TextField extends Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
}
onChange = ({ target }) => {
this.setState({ value: target.value });
};
render() {
return <input onChange={this.onChange} {...this.props}>
{this.state.value}
</input>
}
}
export default TextField;
The problem is happening when I type something on the input, the inputs disappeared and got this error message on the console:
The above error occurred in the <input> component
and this one
Uncaught Invariant Violation: input is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.

Change:
render() {
return <input onChange={this.onChange} {...this.props}>
{this.state.value}
</input>
}
To:
render() {
return <input defaultValue={this.state.value} onChange={this.onChange} {...this.props} />
}
Or (depending on the behavior your want):
render() {
return <input value={this.state.value} onChange={this.onChange} {...this.props} />
}
The existing code is trying to set the child of input to {this.state.value}.

Related

In React how to PROPERLY pass input value from child to parent

I have a simple code in [sandbox][1] and below
[1]: https://stackblitz.com/edit/react-72dprn to pass input form value to child to parent but something is wrong and the value didn't get passed.
This is the app.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import Form from './form'
class App extends Component {
constructor() {
super();
this.state = {
value: ""
};
}
handleSubmit = e=>{
this.setState({
value=e.target.value
})
}
render() {
return (
<div>
<Form onSubmit={this.handleSubmit}/>
</div>
);
}
}
render(<App />, document.getElementById('root'));
And the Form.js
import React, { Component } from 'react';
class form extends Component {
render() {
return (
<form className="replyForm" onSubmit={this.props.onSubmit}>
<input />
<button type="submit" className='btn btn-success'>Submit</button>
</form>); } }
export default form;
Any help greatly appreciated!
There are so many mistakes in your code. You should read the react docs properly
First of all you are setting your state incorrectly -
handleSubmit = e=>{
this.setState({
value: e.target.value //this is an object don't assign a value//
})
}
Second - In your form.js your component starts with a lowercase. React components start with an uppercase -
class Form extends Component {
render() {
return (
<form className="replyForm" onSubmit={this.props.onSubmit}>
<input />
<button type="submit" className='btn btn-success'>Submit</button>
</form>); } }
export default Form;
Now coming to your original question, To pass the value of input to child you need to pass it as props and use it in child as props -
<Form onSubmit={this.handleSubmit} inputValue={this.state.value} />
In your child component access that value as this.props.value.

How to create a to-do list in React without ref

I intend to create a to-do list without using ref as in the many examples, but it isn't working.
The expected behavior is that upon entering an entry, it will show up at the top and upon clicking add, it will create an input box for entering an entry. Currently, upon entering the state returns undefined.
The code can be found below or in this sandbox:
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
constructor() {
super();
this.state = {
todos: []
};
}
onChange=(e)=>{
const newToDos = [...this.state.todos]
newToDos.push(e.target.value)
this.setState({
todos: newToDos
})
}
onAdd=(e)=>{
e.preventDefault();
const newtodos=[...this.state.todos]
this.setState({
todos: newtodos.push("")
})
}
render() {
console.log(this.state.todos)
return (
<div>
<p>All the to-dos include {this.state.todos}</p>
<ToDo
todos={this.state.todos}
/>
<form onSubmit={this.onChange}>
<input
type="text"
placeholder="add a new todo..."
/>
</form>
<button onClick={this.onAdd}>+</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
And here is the todo.js:
import React, { Component } from 'react';
import { render } from 'react-dom';
export default class ToDo extends Component {
constructor(props){
super(props)
}
render() {
const {todos, onChange}=this.props
return (
<div>
{
todos.map((todo, index)=>
<div>
{todo}
</div>
)
}
</div>
);
}
}
You can store your new todo in state when onChange input and add this into todos when click save.
I have forked and edit your sample.
https://stackblitz.com/edit/react-nwtp5g?file=index.js
BTW: In your sample, newtodos.push("") will return the length of newtodos array, not the array after pushed.
onAdd=(e)=>{
e.preventDefault();
const newtodos=[...this.state.todos]
this.setState({
todos: newtodos.push("")
})
Hope this help.
your code newtodos.push("") dosent return array so no map function:
this.setState({
todos: newtodos.push("")
})
correct it something like this
this.setState({
todos: newtodos.concat("new value")
})
You have a problem with this code,
<form onSubmit={this.onChange}>
<input
type="text"
placeholder="add a new todo..."
/>
</form>
Here you are adding onSubmit on form, which will never call because you don't have submit button.
you should do something like this,
<form>
<input
type="text"
placeholder="add a new todo..."
onChange={this.onChange}
value={this.state.currentValue}
/>
</form>
onChange=(e)=>{
event.preventDefault();
this.setState({
currentValue: e.target.value
})
}
onAdd=(e)=>{
e.preventDefault();
const newToDos = [...this.state.todos]
newToDos.push(this.state.currentValue)
this.setState({
todos: newToDos,
currentValue: ''
})
}
Demo
Update
In your todo component you have useless constructor, If you don't have state in a component or don't have any function to bind this don't add constructor.
You can remove the constructor.
Another thing is, you are not passing any onChange prop to todo component, so here you will get undefined for onChange.
const {todos, onChange}=this.props
You can also write this component as a functional component.
You can update your code with
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
constructor() {
super();
this.state = {
todos: [],
inputText: ""
};
}
onAdd= () => {
this.setState({
todos: [...this.state.todos, this.state.inputText], textInput: ""
})
}
render() {
console.log(this.state.todos)
return (
<div>
<p>All the to-dos include {this.state.todos}</p>
<ToDo
todos={this.state.todos}
/>
<form>
<input
type="text"
placeholder="add a new todo..."
onChange={inputText => this.setState({inputText})}
/>
</form>
<button onClick={this.onAdd}>+</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
And in todo.js you can simply do
import React, { Component } from 'react';
import { render } from 'react-dom';
export default const ToDo = ({todos}) => {
return(<div>
{todos.map((todo, index) => (
<div key={index}>
{todo}
</div>))}
</div>)}
as it do not contains any state associated with it.

How can get Value from child component in react?

I create a InputComponent and I want to import this component in other component and do submit, but I can't do it. how can I get value from child component in my FormComponent
InputComponent.js
import React, {Component} from 'react';
class InputComponent extends Component {
constructor(props) {
super(props);
this.state = { currentVal: null }
}
render() {
return (
<div>
<input
value={this.state.currentVal}
onChange={(event) => this.setState({currentVal:event.target.value })}
/>
</div>
);
}
}
export default InputComponent;
FormComponent.js
import React,{Component} from 'react';
import InputComponent from '../../components/common/InputComponent';
class FormComponent extends Component {
constructor(props) {
super(props);
this.state = { }
}
CallSubmit= (event) => {
// how can get username and password ?
event.preventDefault();
console.log(event.target.vale)
}
render() {
return (
<div style={{width:100, height:500, marginTop:100}}>
<form onSubmit={ this.CallSubmit }>
<InputComponent name="username" />
<InputComponent name="password" />
<button>Send it</button>
</form>
</div>
);
}
}
export default FormComponent;
You can create an onChange action on child component, for example here is your FormComponent:
Create this function to handle change:
onChangeUsername(username){
this.setState({username})
}
Passing the props to child component:
<InputComponent name="username" onChange = {this.onChangeUsername} />
And in the child component(InputComponent), you can access this props and pass the data to it:
this.props.onChange(event.target.value)
move your onChange functions in parent component and store username and password in FormComponent component
In React, data flows one way, from parent to children.
Therefore, you need to have the input' actual states at the FormComponent and pass them as props to the InputComponent, and the function that deals with it at the FormComponent either.
<div>
<InputComponent
input={this.state.username}
onChange={this.handleInputChange}
/>
<InputComponent
input={this.state.password}
onChange={this.handleInputChange}
/>
</div>
A good article to understand it: https://openclassrooms.com/en/courses/4286486-build-web-apps-with-reactjs/4286721-understand-one-way-data-bindings

can i pass a state value with the jsx code ?? in reactjs

Hello everybody I'm wondering if I can pass a state value from a component to other where I'm returning jsx code to be displayed for example I have 3 components.
1
import React, { Component } from 'react';
import Conteneur from './Conteneur';
class Header extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
<Conteneur values={this.state.value} />
</form>
);
}
}
export default Header;
2 app.js
import React, { Component } from 'react';
import Header from './Header';
import Conteneur from './Conteneur';
import './App.css';
class App extends Component {
render() {
return (
<div className="App" >
<br />
<Header />
<br />
<Conteneur />
</div>
);
}
}
export default App;
3 and finally
import React, { Component } from 'react';
const Conteneur = () => {
return (
<div className="tab"><span>ok test </span></div>
);
};
export default Conteneur;
I like to pass the state value of header that I have from the input to conteneur and then display in the box while I have some code all the examples that I saw online they are sending state like this:
class Dashboard extends Component {
...
...
render(){
return(
<Sidebar data={this.state.data1}/>
);
}
}
So can I do like this <Conteneur values={this.state.value} /> in the form ?
And I imported Conteneur.
i updated the code but the output is
Yes you can do, only one thing you are missing. Receive the props in the function parameters then render that in the ui.
Like this:
const Conteneur = (props) => {
return (
<div className="tab"><span>value: {props.value} </span></div>
);
};

How to make dependence between two form filters in ReactJS

I have three classes in my ReactJS app. Here they are :
class FirstFilter extends React.Component {
constructor() {
super();
this.state = {
val1: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<Label>
<Input type="select" value={this.state.value} onChange={this.props.handleChange}>
<option disabled selected value>Select plox</option>
<option value='Firdt'>First</option>
<option value='Second'>Second</option>
</Input>
</Label>
);
}
}
class SecondFilter extends React.Component {
constructor() {
super();
this.state = {
val2: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.val2});
}
render() {
return (
<Label>
<Input type="search" placeholder="Print somthing" value={this.state.value} onChange={this.props.handleChange}>
</Input>
</Label>
);
}
}
class Main extends React.Component {
constructor() {
super();
this.state = {
val1: '',
val2: ''
};
this.handleChangeVal1 = this.handleChangeVal1.bind(this);
this.handleChangeVal2 = this.handleChangeVal2.bind(this);
}
handleChangeUUID(event) {
this.setState({val1: event.target.value.toLowerCase()});
}
handleChangeOrigin(event) {
this.setState({val2: event.target.value.toLowerCase()});
}
render() {
return (
<div>
<Form inline>
<FormGroup>
<div>
<UuidRow handleChange = {this.handleChangeVal1} />
</div>
<div>
<OriginRow handleChange = {this.handleChangeVal2} />
</div>
</FormGroup>
</Form>
</div>
);
}
}
I want make SearchField from second filter empty when i check whatever in my DropDownList from first filter. When i only change value in my Main it's still leave typed text there. Maybe I doing something wrong and didn't understand basic hierarchy?
You should pass props to your child component, SearchField, when the state of the parent, Main, has been updated by the callback invoked by the DropDownList. The code in your example isn't consistent, so I can't guess what I need to change to help you, but here is a very basic example of how setting state in the parent via a callback event handler passed to one child (text input) can be used to set props on the second child (text area):
https://codesandbox.io/s/BLwl1y6j2
main.js
import React, { Component } from 'react';
import { render } from 'react-dom';
import FirstChild from './FirstChild';
import SecondChild from './SecondChild';
class Main extends Component {
constructor(props) {
super(props);
this.state = {
val1: '',
};
}
// callback to pass as prop to child element text input
handleChangeVal1 = (event) => {
// sets parent state
this.setState({val1: event.target.value.toLowerCase()});
}
render() {
return (
<div>
<FirstChild handleChange = { this.handleChangeVal1 } value={ this.state.val1 }/>
<SecondChild value={ this.state.val1 }/>
</div>
);
}
}
render(<Main />, document.getElementById('root'));
FirstChild.js
import React, {Component } from 'react';
class FirstChild extends Component {
// input calls handleChange callback passed in props to modify parent component state
render() {
console.log(this.props.value);
return (
<input type="text" value={this.props.value} onChange={this.props.handleChange}/>
);
}
}
export default FirstChild;
SecondChild.js
import React, { Component } from 'react';
class SecondChild extends Component {
// render text area with value passed in props
render() {
console.log(this.props.value);
return (
<textarea value={this.props.value} onChange={this.props.handleChange}/>
);
}
}
export default SecondChild;

Resources