Parent not Successfully Retrieving Data from Child - reactjs

I have a callback function in a parent component passed to an child component that should retrieve the input once submission in the child component takes place but is not working as expected. No data is being retrieved by the parent. Here is my code:
Parent:
class App extends Component {
constructor(props) {
super(props)
this.state = { item: '' }
}
getItem(item) {
this.setState({
item: item
})
console.log(this.state.item);
}
render() {
return (
<div className="App">
<Input getItem={this.getItem} />
<h2>{this.state.item}</h2>
</div>
);
}
}
Child:
class Input extends Component {
constructor(props) {
super(props)
this.state = { value: '' }
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
})
console.log(this.state.value)
}
handleSubmit(e) {
{this.props.getItem(this.state.value)};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" name={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="+" />
</form>
</div>
)
}
}

Solution 1 :
Use fat arrow in getItem function like this :
getItem = (item) => {
this.setState({
item: item
})
console.log(this.state.item);
}
Solution 2 :
Bind getItem function in counstructor like :
constructor(props) {
super(props)
this.state = { item: '' }
this.getItem = this.getItem.bind(this);
}
Solution 3 :
Bind getItem function in input directly :
<Input getItem={this.getItem.bind(this)} />

You should bind the getItem context to the App class.
You can do this by doing
<Input getItem={this.getItem.bind(this)} />
or by using the arrow function when you define getItem
or by binding the method in the constructor as you did for the child component

Related

Why is this.setState not updating in my click function?

I am trying to update my state by using a click function. However for some reason it is not updating. Could someone please explain to me what I am doing wrong?class Textbox extends
Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'jkjkljkljl'
}
}
handle(event) {
const myValue = event.target.value;
this.setState({
text: myValue
})
console.log(this.state)
}
render() {
return (
<div>
<textarea className="Textbox" rows="2" cols="30" type = "text" >
</textarea>
<button className="postbutton" onClick={this.handle.bind(this)}>Post</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
export default Textbox;
Here is an updated version of your code that works.
Issue was that you were trying to set the value of the button to the state.
What you should do is setup textarea as a controlled input (have value and onChange setup as I did below) and use that value on click.
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
textArea: "",
text: "jkjkljkljl"
};
}
handle(event) {
console.log(event);
this.setState({
text: this.state.textArea
});
console.log(this.state);
}
handleChange(event) {
this.setState({ textArea: event.target.value });
}
render() {
return (
<div>
<textarea
className="Textbox"
rows="2"
cols="30"
value={this.state.textArea}
onChange={this.handleChange.bind(this)}
/>
<button className="postbutton" onClick={this.handle.bind(this)}>
Post
</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
It seems you are trying to handle a form using React/JSX. There are great libraries for this purpose (React Forms).
This is the proper code:
class App extends React.Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'Static'
}
}
handleOnChange(event) {
this.setState({text: event.target.value});
}
handleSubmit(event) {
if (event.keyCode == 13) return this.sendData();
}
render() {
return (
<div>
<form onKeyUp={this.handleOnChange}>
<textarea className="Textbox"
rows="2" cols="30" type="text"
>
</textarea>
<button className="postbutton"
onClick={this.handleSubmit.bind(this)}>
Post
</button>
</form>
<h1>{this.state.text}</h1>
</div>
);
}
}
React.render(<App />, document.getElementById('app'));
In your example, you are binding the state to the root of the button and not the textarea. If you want a static example (whereas the above code changes as you type), you may simply handle the enter key via if (event.keyCode == 13) return this.sendData() and remove the onChange.

Parent Component Reverting to Initial State After Updating State w/ Callback in Child

I am sending a callback function from a parent to a child component, and although the parent successfully updates it's state based on input provided to the child, it immediately reverts back to initial state, thus resulting in the browser briefly flashing the input that was provided and then displaying the initial state. What is the fix for this? Here is my code:
Parent:
class App extends Component {
constructor() {
super()
this.state = { item: '' }
this.getItem=this.getItem.bind(this);
}
getItem(val) {
this.setState({
item: val
})
console.log(this.state.item);
}
render() {
return (
<div className="App">
<Input getItem={this.getItem} />
<h2>{this.state.item}</h2>
</div>
);
}
}
Child:
class Input extends Component {
constructor(props) {
super(props)
this.state = { value: '' }
this.handleChange=this.handleChange.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
})
console.log(this.state.value)
}
handleSubmit(e) {
{this.props.getItem(this.state.value)};
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" name={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="+" />
</form>
</div>
)
}
}
I was able to solve this by using e.preventDefault() in the handleSubmit function.

React - pass dynamic value to child

I have an app that uploads files via a standard <input type="file"/>. I'm trying to pass the file size of the chosen file(s) to the child to see if it's above a certain size, and if so, display an error. I know you have to pass state values down as props, but I'm unsure as to where/how to call the function to get an updated value. Any help is appreciated.
Edit: I am using the react jsonschema form to build the form: https://github.com/mozilla-services/react-jsonschema-form. Declaring the schemas before the Parent class.
Parent
const schema = {
type: 'object',
required: ['file'],
properties: {
file: { type: 'string', format: 'data-url', title: 'File' }
}
}
const FileWidget = (props) => {
return (
<input type="file" id="fileName" required={props.required} onChange={(event) => props.onChange(event.target.value)} />
)
}
const uiSchema = {
file: {
'ui:widget': FileWidget,
classNames: "uiSchema"
}
}
class Parent extends Component {
constructor(props) {
super(props);
this.state = { fileSize: 0 };
this.getFileSize = this.getFileSize.bind(this);
getFileSize(){
this.setState({fileSize: document.getElementById("fileName").files[0].size});
console.log("FILESIZE:: ", this.state.fileSize);
} //where to call to update the file size?
render() {
return (
<div className="container">
<FileUpload schema={schema} uiSchema={uiSchema} fileSize={this.state.fileSize} />
</div>
)
}
}
export default Parent;
Child
class Child extends Component {
constructor(props) {
super(props);
this.state = { formData: {} };
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div className="container">
<Form
schema={this.props.schema}
uiSchema={this.props.uiSchema}
formData={this.state.formData}
onChange={({ formData }) => this.setState({ formData })}
onSubmit={this.handleSubmit}
>
<div>
<button type="submit" className="btn btn-info">Convert</button>
</div>
</Form>
<div hidden={this.props.fileSize > 100 ? false : true }><h4>File size exceeded.</h4></div>
</div>
)
}
}
export default Child;
class Parent extends Component {
constructor(props) {
super(props);
this.state = { fileSize: 0 };
this.getFileSize = this.getFileSize.bind(this);
getFileSize(){
this.setState({fileSize: document.getElementById("fileName").files[0].size});
console.log("FILESIZE:: ", this.state.fileSize);
} //where to call to update the file size?
componentDidMount(){
// you can call the getFilesize here
this.getFileSize();
}
render() {
return (
<div className="container">
<FileUpload fileSize={this.state.fileSize} />
</div>
)
}
}
export default Parent;
child Component
class FileUpload extends Component {
constructor(props) {
super(props);
this.state = { formData: {} };
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div className="container">
<Form
formData={this.state.formData}
onChange={({ formData }) => this.setState({ formData })}
onSubmit={this.handleSubmit}
>
<div>
<button type="submit" className="btn btn-info">Convert</button>
</div>
</Form>
<div style={{display:this.props.fileSize > 100 ? "block": "none" }><h4>File size exceeded.</h4></div>
</div>
)
}
}
export default FileUpload;
I think you want to show the error message when file size exceeds given size
you can also use componentWillMount to call getfilesize
it actually depends document.getElementById("fileName")
it that particular element has populated the data by the time your parent componentWill Mount you can use componentWillMount lifecycle hook
Parent Component
class App extends Component {
constructor(props) {
super(props);
this.state = {};
}
onFileSelected(e) {
var fileSize = e.target.files.length > 0 ? e.target.files[0].size : false;
if (fileSize)
this.setState({ fileSize });
}
render() {
return (
<div className="App">
<input type="file" onChange={this.onFileSelected.bind(this)} />
<FileUpload fileSize={this.state.fileSize}></FileUpload>
</div>
);
}
}
child Component
class FileUpload extends Component {
render() {
return (
<div>
{this.props.fileSize > 100 ? <h2 >File size exceeds 100</h2> : null}
</div>
);
}
}
in the above code what i did is created <input type="file"/> in parent component and attached a onchange event to it.
Got it to work. Passed the function to the child:
<FileUpload fileSize={this.getFileSize.bind(this)} />
Then in the child added a setState to the form's onChange to call the function:
onChange={({ formData }) => { this.setState({ formData }); this.setState({fileSize:this.props.fileSize()})}}
and displayed the error message accordingly:
<div style={{display: this.state.fileSize > 100 ? "block": "none" }><h4>File size exceeded.</h4></div>

How can I get <textarea> value in parent component from child?

The aim of my application is to get some array of messages(mes) from api-url and send answer(subFunction method) for every message. After that message will be delete from 'mes' array. 'Message' is a parent component responsible for fetch data(componentDidMount event) and rendering message through map method. 'MessageItem' responsible for get value from 'textarea' - the body of answer. But I can't transfer this.state.value(textarea.value) from from MessageItem to parent component. If I place 'subFunction' in child component, I can't change this.state.mes
import React from 'react'
import ReactDOM from 'react-dom'
const url="api-url";
class MessageItem extends React.Component {
constructor(props) {
super(props);
this.state = {
value:'',
};
};
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<div className="message_wrap" key={this.props.message_id}>
<div className="message_body">
{this.props.message_body}
</div>
<div className="input-field col s12">
<textarea value={this.state.value} onChange={this.handleChange.bind(this)}/>
<label htmlFor="textarea1">
Ответ
</label>
<button onClick={this.props.onClick}>
Отправить
</button>
</div>
</div>
);
}
}
class Message extends React.Component {
constructor(props) {
super(props);
this.state = {
mes:[],
};
};
componentDidMount(){
fetch(url).then(function(response){
return response
}).then(function (response) {
return response.json()
}).then((data)=>{
this.setState({mes:data})
})
}
subFunction(user_id, value) {
/*This method have to send answer with user id and textarea value*/
}
render() {
return (
<div>
{this.state.mes.map((index)=>
(
<MesItem
key={index.message_id}
message_body={index.message_body}
onClick={this.subFunction.bind(this, index.user_id)}
/>
)
)
}
</div>
);
}
}
ReactDOM.render(<Message/>, document.getElementById('container'));
You are passing a function from parent component to child, call that function to pass the value from child to parent.
Like this:
<button onClick={() => this.props.onClick(this.state.value)}>
Отправить
</button>
Now do console.log inside subFunction it will print proper value:
subFunction(user_id, value) {
console.log(user_id, value)
}
Assign a ref to the textarea in the child component and to the MesItem and then you can fetch the value like
class MessageItem extends React.Component {
constructor(props) {
super(props);
this.state = {
value:'',
};
mesItem = [];
};
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<div className="message_wrap" key={this.props.message_id}>
<div className="message_body">
{this.props.message_body}
</div>
<div className="input-field col s12">
<textarea value={this.state.value} ref={(ta) => {this.text = ta}}onChange={this.handleChange.bind(this)}/>
<label htmlFor="textarea1">
Ответ
</label>
<button onClick={this.props.onClick}>
Отправить
</button>
</div>
</div>
);
}
}
class Message extends React.Component {
constructor(props) {
super(props);
this.state = {
mes:[],
};
};
componentDidMount(){
fetch(url).then(function(response){
return response
}).then(function (response) {
return response.json()
}).then((data)=>{
this.setState({mes:data})
})
}
subFunction(user_id, i) {
console.log(this.mesItem[i].text.value)
}
render() {
return (
<div>
{this.state.mes.map((index, i)=>
(
<MesItem
ref = {(ip) => {this.mesItem[i] = ip}}
key={index.message_id}
message_body={index.message_body}
onClick={this.subFunction.bind(this, index.user_id , i)}
/>
)
)
}
</div>
);
}
}
ReactDOM.render(<Message/>, document.getElementById('container'));

React - _this2.SetState is not a function

I'm trying to create a component that will print out input text to the screen, here is what I'm working on.
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
}
render() {
return (
<div className="search-bar">
<input value={this.state.term} onChange={event => this.SetState(event.target.value)} />
The value of input is: {this.state.term}
</div>
);
}
}
However I keep getting an error in Chrome console:
bundle.js:19818 Uncaught TypeError: _this2.SetState is not a function
Any ideas?
Thanks
Try this:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
this.setInputState = this.setInputState.bind(this);
}
setInputState(event) {
this.setState({ term: event.target.value });
}
render() {
return (
<div className="search-bar">
<input value={this.state.term} onChange={this.setInputState} />
The value of input is: {this.state.term}
</div>
);
}
}
you have to bind {event => this.SetState(event.target.value)} function to component this. problem is your onChange function not running your component this context
code should look something like this
const onChange = (event) => { this.setState({term:event.target.value}) }
<input value={this.state.term} onChange={onChange.bind(this) />
I think you need to bind your this, try this (no pun intended).
render() {
return (
<div className="search-bar">
<input value={this.state.term} onChange={event => this.setState.bind(this, event.target.value)} />
The value of input is: {this.state.term}
</div>
);
}
I believe you had to specify what was changed in the state:
this.setState({ term: event.target.value });
instead of
this.setState( event.target.value );
Try this code:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
}
render() {
return (
<div className="search-bar">
<input value={this.state.term} onChange={event => this.setState({term:event.target.value})} />
The value of input is: {this.state.term}
</div>
);
}
}
This worked for me. I think you missed out on the state key name term and also this SetState, which should be setState. Just follow my example below am sure it will work for you also.
class Square extends React.Component {
constructor(props){
super(props)
this.state = {
value: null
};
}
render() {
return (
<button
className="square"
onClick={()=> this.setState({value:'X'})}>
{this.state.value}
</button>
);
}
}
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
}
render() {
return (
<div className="search-bar">
<input value={this.state.term} onChange={event => this.SetState(event.target.value)} />
The value of input is: {this.state.term}
</div>
);
}
}
you wrote SetState instead of
I faced a similar problem and noticed that I was using this.state.setState() method instead of this.setState().
Although OP's problem is the wrong capitalization.

Resources