React-native form not typing in TextInput - reactjs

Giving the components below, I am unable to type in TextInput the letter is written and then deleted, it seems a problem with updating the state. Any clue?
class myContainerComponent extends Component {
constructor(props) {
super(props)
this.onChange = this.onChange.bind(this)
}
onChange(value) {
this.setState({
value
})
}
render() {
return (
<PresentationalComponent
onChange={this.onChange}
value={this.state.value}
/>
)
}
}
class PresentationalComponent extends Component {
render() {
return(
<TextInput
onChangeText={this.props.onChange}
value={this.props.value}
/>
)
}
}
Any clue?

You should initialise your state in your constructor:
constructor(props){
super(props);
this.state = {
value: ''
}
}

Add this to your myContainerComponent constructor:
this.state = {
value: '',
}

I believe both other answers are correct but you could simplify your code even more and get rid of the constructor declaration using an arrow function:
class myContainerComponent extends Component {
state = {
value: ''
}
onChange = (value) => {
this.setState({
value
})
}
render() {
return (
<PresentationalComponent
onChange={this.onChange}
value={this.state.value}
/>
)
}
}

import * as React from 'react';
import { TextInput } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: {}
};
this.onChange = this.onChange.bind(this)
}
onChange(value) {
this.setState({
value
})
}
render() {
return (
<PresentationalComponent
onChange={this.onChange}
value={this.state.value}
/>
)
}
}
class PresentationalComponent extends React.Component {
render() {
return(
<TextInput
onChangeText={this.props.onChange}
value={this.props.value}
/>
)}
}

Related

how to make a 'number' component in react native

I want to make a 'number' component which accepts numbers on input.
I tried to make it, but it is not working.
Here the code-
import React, { Component } from 'react';
import { TextInput } from 'react-native';
constructor(props)
{
super(props);
this.state = {
text: ''
};}
handleInputChange = (text) => {
if (/^\d+$/.test(text)) {
this.setState({
text: text
});
}
}
const NumberInput = (props) => {
return (
<TextInput
keyboardType='numeric'
onChangeText={this.handleInputChange}
value={this.state.text}
/>
)
}
export { NumberInput };
You don't have access to this in functional component, you need to define it as class based component,
class NumberInput extends Component{
constructor(props){
super(props);
this.state = {
text: ''
};
}
handleInputChange = (text) => {
if (/^\d+$/.test(text)) {
this.setState({
text: text
});
}
}
render(){
return (
<TextInput
keyboardType='numeric'
onChangeText={this.handleInputChange}
value={this.state.text}
/>
)
}
}
Update
You can also try this,
<TextInput
keyboardType='numeric'
onChange={this.handleInputChange} //onChange instead of onChangeText
value={this.state.text}
/>
And your function should be,
handleInputChange = (e) => {
if (/^\d+$/.test(e.target.value)) {
this.setState({
text: e.target.value
});
}
}
Reference to this change.
Also, you can use Number() function to check if the input is a number. It not, it will return NaN
you should use the class component when to use the constructor and use super or use and used hock function with useState in react
class NumberInput extends Component{
constructor(props){
super(props);
this.state = {
text: ''
};
}
handleInputChange = (text) => {
if (/^\d+$/.test(text)) {
this.setState({
text: text
});
}
}
render(){
return (
<TextInput
keyboardType='numeric'
onChangeText={this.handleInputChange}
value={this.state.text}
/>
)
}
}
or using the following shape when used the function component
import useState from'react'
function NumberInput (){
const [text, setText] = useState('');
handleInputChange = (text) => {
if (/^\d+$/.test(text))(setText(text)) ;
}
}
return (
<TextInput
keyboardType='numeric'
onChangeText={this.handleInputChange}
value={text}
/>
)
}
}

Passing an object as props and receiving it

I have a component Data and its child component BarChart.
Data component looks as following:
export default class Data extends Component {
constructor(props) {
super(props);
this.state = {
data: {
labels: [],
datasets: [{
label: "",
data: [],
backgroundColor: ''
}]
}
}
}
componentWillMount() {
this.geData();
}
geData = () => {
let labelsData = someContent;
let datasets = otherContentl;
this.setState({data: {...this.state.data, labels: labelsData, datasets: datasets}}, ()=>{console.log(this.state.data)});
}
render(){
return (
<BarChart data={this.state.data} />
);
}
}
When I check the result of console.log(this.state.data) in getData function, it prints out the correct data.
However, when I receive the props in BarChart component, I only receive datasets key filled with the correct data, but labels key is an empty array.
export default class BarChart extends Component {
constructor(props) {
super(props);
console.log(props);
}
componentWillMount() {
this.setState({chartData: this.props.data});
}
render() {
return (
<div className="barChart">
<Bar
data={this.state.chartData}
/>
</div>
);
}
}
Why does that happen? How can it be fixed?
What I had in BarChart component is:
constructor(props) {
super(props);
this.state = {
chartData: {}
}
}
componentWillMount() {
this.setState({chartData: this.props.data});
}
render() {
return (
<div className="barChart">
<Bar
data={this.state.chartData}
/>
</div>
);
}
What I changed is receiving the props immediately and using it, instead of receiving it in state or componentWillMount:
export default class BarChart extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentWillMount() { }
componentDidMount() { }
render() {
return (
<div className="barChart">
<Bar
data={this.props.data}
/>
</div>
)
}
}
So, whenever the props is changed, the component will re-render.

How to setProps in ReactJS

I have 2 Components one called NodeWidget and another called PopupWidget. In the NodeWidget it has a Model assigned to it which looks like the following:
PopupModel
export class PopupModel {
question: string;
model: string;
constructor(question: string, model: string) {
this.question = question;
this.model = model;
}
}
The parent Component is NodeWidget which passes in the Model to the PopupWidget with data in.
NodeWidget
{ this.state.showComponent ?
<PopupWidget model={this.props.popupModel} /> :
null
}
Then finally in the child Component we have this code:
export interface PopupWidgetProps {
model: PopupModel;
}
export interface PopupWidgetState { }
export class PopupWidget extends React.Component<PopupWidgetProps, PopupWidgetState> {
constructor(props: PopupWidgetProps) {
super(props);
this.state = { };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this.props);
}
render() {
return (
<div className="popup">
<div className="popup_inner">
<h1>TEST</h1>
<input type="text" value={this.props.model.question} placeholder="Write a question..." />
<button onClick={this.handleClick}>close me</button>
</div>
</div>
);
}
}
I want to be able to bind the value of the input to the model and then for it to update the original model in the Parent Component, am i doing this correctly as it does not seem to work.
You can do this to pass the input result to parent component on the button click:
PopupWidget :
export class PopupWidget extends React.Component<PopupWidgetProps, PopupWidgetState> {
constructor(props: PopupWidgetProps) {
super(props);
this.state = { question: '' };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.inputResult(this.state.question)
}
render() {
return (
<div className="popup">
<div className="popup_inner">
<h1>TEST</h1>
<input type="text" value={this.state.question} onChange={(question) => { this.setState({ question })}} placeholder="Write a question..." />
<button onClick={this.handleClick}>close me</button>
</div>
</div>
);
}
}
NodeWidget :
constructor(props) {
super(props);
this.getInputResult = this.getInputResult.bind(this);
}
getInputResult(question) {
this.props.inputResult(question);
this.setState({ showComponent: false });
}
...
{ this.state.showComponent ?
<PopupWidget inputResult={this.getInputResult} /> :
null
}
Finally in PopupModel (i assume this is a react component, i don't know if you can work with simple es6 class in react):
export class PopupModel extends React.Component {
constructor(props) {
this.state = { question: '', model: '' }; // set your initial state
this.getInputResult = this.getInputResult.bind(this);
}
getInputResult(question) {
this.setState({ question }); // here's our result from the input
}
render(){
return(<NodeWidget inputResult={this.getInputResult} />);
}
}
This can be pretty boring to handle if you have multiple components between the two which have to communicate.
You can use a HOC like Redux or MobX to handle an app state that can be passed in any component, and any component can dispatch actions to update the app state, you should go for it if you have multiple cases like this.

React - how to update state in parent component onclick in child - what am I doing wrong?

I have a parent and child component and simply take the input and on click I want to sort of update the parent. My onChange function works, but onClick I get the error message: Cannot read property 'name' of undefined - meaning that I never actually updated the parent. I cant figure out what am I doing wrong because as I understand, Im am passing the function correctly. Anyone knows? Thanks!
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {name: 'Frarthur'};
this.changeName = this.changeName.bind(this);
}
changeName(newName) {
this.setState({
name: newName
});
}
handleInput() {
console.log("helloooooo", this.state.name)
}
render() {
return (
<div>
<Child name={this.state.name} onChange={this.changeName} onClick={this.handleInput}/>
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleInput2 = this.handleInput2.bind(this);
}
handleChange(e) {
const name = e.target.value;
this.props.onChange(name);
}
handleInput2() {
this.props.onClick()
}
render() {
return (
<div>
<h1>
Hey my name is {this.props.name}!
</h1>
<input onChange={this.handleChange}/>
<input type="submit" onClick={this.handleInput2}/>
</div>
)
}
}
You could bind them in your constructor, like you did w/ changeName:
constructor(props) {
super(props);
this.state = {name: 'Frarthur'};
this.changeName = this.changeName.bind(this);
this.handleInput = this.handleInput.bind(this);
}
Alternatively, you could apply the proposed ES7 functionality (still considered "experimental" but extremely likely to be supported) property initializer by using fat arrow function:
handleInput = () => {
console.log("helloooooo", this.state.name)
};
Note, this may require you to update your project's configuration to support stage-0 preset for babel.
You haven't bind the
handleInput()
method in the Parent component. Here is the corrected Parent component
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { name: 'Frarthur' };
this.changeName = this.changeName.bind(this);
this.handleInput = this.handleInput.bind(this);
}
changeName(newName) {
this.setState({
name: newName
});
}
handleInput() {
console.log("helloooooo", this.state.name)
}
render() {
return (
<div>
<Child name={this.state.name} onChange={this.changeName} onClick={this.handleInput} />
</div>
)
}};

Change button text dynamically in material-ui

If I try to change label button I got an error because label is a read only property.
How could I change button text dinamically?
export default class Tagger extends Component {
static propTypes = {
name: PropTypes.string
}
constructor(props) {
super(props)
this.state = {
disabled: true
}
this.enableEdit = this.enableEdit.bind(this)
}
componentDidMount() {
this.editButton = React.findDOMNode(this.refs.editButton)
}
enableEdit() {
this.setState({disabled: !this.state.disabled})
this.refs.editButton.props.label = 'Save'
}
render() {
return (
<div>
<RaisedButton onClick={this.enableEdit} label='Modify' primary={true} ref='editButton' />
</div>
)
}
}
Props are read-only , you can't mutate/edit them
You can simply change the props instead of mutating them. Set the value of the prop to state and simply pass it.
export default class Tagger extends Component {
static propTypes = {
name: PropTypes.string,
}
constructor(props) {
super(props)
this.state = {
disabled: true,
label = "Modify" // initial state
}
this.enableEdit = this.enableEdit.bind(this)
}
componentDidMount() {
this.editButton = React.findDOMNode(this.refs.editButton)
}
enableEdit() {
this.setState({
disabled: !this.state.disabled,
label:"Save" // update it here
})
}
render() {
// take value from state and pass it, no need for ref
return (
<div>
<RaisedButton onClick={this.enableEdit} label={this.state.label} primary={true} />
</div>
)
}
}
You should use state instead of refs.
export default class Tagger extends Component {
constructor(props) {
super(props)
this.state = {
disabled: true,
label: 'Modify'
}
this.enableEdit = this.enableEdit.bind(this);
}
enableEdit() {
this.setState({disabled: !this.state.disabled, label: 'Save'});
}
render() {
return (
<div>
<RaisedButton onClick={this.enableEdit} label={this.state.label} primary={true} />
</div>
)
}
}

Resources