why i can not use passed refs in input element - reactjs

I am trying to focus on error fields inside of a form and I am using ref to do that but somehow ref always returns null and I am getting errors, I want to use/pass this ref to focus on error field , here error is stored in state which i have not included in code
here is the basic code,
class Form extends Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
this.getErrors = this.getErrors.bind(this);
}
componentWillUnmount() {
/////
}
renderSubmitAction() {
if(errors) {
this.textInput.current.focus();
}
}
render() {
return (
<View key={propertyName}>
<FormInput
id={id_prefix + propertyName}
key={propertyName}
ref={this.textInput}
/>
</View>
)
const submitButton = this.renderSubmitAction();
return (
<View key={this.state.submitId} style={props.style}>
{children}
{props.children}
{submitButton}
</View>
);
}

Problem
You are running this:
this.textInput.current.focus();
before this happens:
<FormInput
id={id_prefix + propertyName}
key={propertyName}
ref={this.textInput}
/>
Solution
I'm not sure what this is supposed to do:
const submitButton = this.renderSubmitAction();
But you probably wanted to use this:
const submitButton = this.renderSubmitAction;

Related

Updating changed value on user interface

I want my value to change on the screen when button is pressed. It does change the variable value behind the scenes but has no effect for the outdated value shown on the screen.
export default class App extends Component {
render() {
this.state = {
myVariable: 'egs'
}
const changeValue = () => {
this.state.myVariable = "CHANGED??!!"
}
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
I expect to update value to the changed one instead of outdated one.
Move state initialization outside of render as well as the changeValue method
You also cannot mutate statue directly, instead use setState()
This should work:
export default class App extends Component {
state = {
myVariable: 'egs'
}
changeValue = () => {
this.setState({myVariable:"CHANGED??!!"})
}
render() {
return (
<View style={styles.container}>
<Text>
{this.state.myVariable}
</Text>
<Button onPress={changeValue} title="CHANGE IT"/>
</View>
);
}
}
this.state.myVariable = "CHANGED??!!"
change to
this.setState({ myVariable: "CHANGED??!!" })

How to use props of a component out of the component in react with typescript?

As i am new to react i have a question.I have a react component and its properties. And I want to reach one of these properties from the page where i used my component.
type BranchProps = {
SelectedBranch : string
}
class Branch extends React.Component<BranchProps, BranchState> {
constructor(props: BranchProps) {
super(props);
}
render() {
return (
<SelectBox></SelectBox>
)
}
}
export default Branch ;
ParentPage.tsx
import Branch...
class Page extends.... {
ctor..
const test:string = () => {
Branch.SelectedBranch ???
}
}
And i want to get "SelectedBranch" from my ParentPage.
Note: SelectedBranch is changing on change event. Should i make my SelectedBranch a const and export it or what should i do ?
I have created this Input.js child component with different props
const Input = ({ placeholder, label, value, onChangeText, secureTextEntry }) => {
return (
<View >
<Text >{ label }</Text>
<TextInput
secureTextEntry={secureTextEntry}
placeholder={placeholder}
autoCorrect={false}
value={value}
onChangeText={onChangeText}
style={inputStyles}
/>
</View>
);
};
Once I import it to be used on a page, this is how the manipulation of the content is being done. the value is been passed on by simply quoting the specific prop
<Input
secureTextEntry
placeholder={'password'}
label={'Password'}
value={this.state.password}
onChangeText={password => this.setState({ password })}
/>
Here the 'password' is been assigned to the component by using the state of the parent. something like this, you can assign the value as you see fit.
state = { email: '', password: '', error: '', loading: false };
A far better way exist by using the Redux approach. would be advisable to have a look.
Firstly, you should understand the difference between state and props inside a component. Props shouldn't be updated, it's the state's role.
You can't directly access component's props outside of it.
In pure react (without librabry like redux) the right way should be to use callbacks to return the element to the parent.
class Branch extends React.Component<BranchProps, BranchState> {
state = {
'selectedBranch': ''
}
constructor(props: BranchProps) {
super(props);
}
handleOnChange = (e) => {
this.setState({'selectedBranch': e.target.value})
this.props.parentHandleChangeBranch(this.state.selectedBranch);
}
render() {
return (
<SelectBox value={this.state.selectedBranch} onChange="{this.handleOnChange}"></SelectBox>
)
}
}
class Page extends React.Component {
state = {
'branch': null
}
parentHandleChangeBranch = (branch) => {
this.setState({'branch': branch};
}
render () {
<div>
<Branch parentHandleChangeBranch={this.parentHandleChangeBranch} />
</div>
}
}
You can declare a function in the parent component and pass it as prop to the child. Then, call this callback whenever you want inside the child.

Pass parameters to prop function without using an arrow function

I've heard that passing an arrow function as a prop is not ideal because it creates a new function every time which will lead to performance issues. However, I'm not entirely sure how to completely move away from them, as can be seen by the example below:
class Home extends Component {
onCardPress = (message) =>{
alert(message)
}
render(){
return(
<View>
<Card
onCardPress={this.onCardPress}
message="Hello world!"
/>
</View>
)
}
}
class Card extends Component {
render(){
const { onCardPress , message } = this.props;
return(
<TouchableOpacity
activeOpacity={0.8}
onPress={()=>{onCardPress(message)}}
/>
)
}
}
I have tried changing onPress in Card to be onPress={onCardPress(message)}, but I know this doesn't work because I am invoking the function rather than passing a function object to the onPress of TouchableOpacity. What is the 'proper' way or best practice to remove the arrow function in TouchableOpacity while still being able to pass the message parameter from the parent component Home?
You could do:
class Card extends Component {
pressHandler = () => this.props.onCardPress(this.props.message);
render() {
return (
<TouchableOpacity
activeOpacity={0.8}
onPress={this.pressHandler.bind(this)}
/>
);
} }
If you want to avoid arrow function, you have to use bind(). Arrow functions will automatically bind "this".
class Home extends Component {
constructor(props) {
super(props);
this.onCardPress = this.onCardPress.bind(this);
}
onCardPress (message) {
alert(message)
}
render(){
return(
<View>
<Card
onCardPress={this.onCardPress}
message="Hello world!"
/>
</View>
)
}
}
class Card extends Component {
render(){
const { onCardPress , message } = this.props;
return(
<TouchableOpacity
activeOpacity={0.8}
onPress={onCardPress(message)}
/>
)
}
}
As I understand it, the issue lies with calling bind inside of render, or returning the handler from yet another lambda, as this will create a new function each time. The conventional way to get around this problem is to bind your handler functions elsewhere -- like in the constructor. In your case, that could look like this:
constructor(props) {
....
this.onCardPress = this.onCardPress.bind(this);
}
...
<Card
onCardPress={this.onCardPress}
message="Hello world!"
/>
Given you alternative option as arrow function already answered in above post.
class Card extends Component {
onClick = () => {
const { onCardPress, message } = this.props;
onCardPress(message);
}
render(){
const { onCardPress , message } = this.props;
return(
<TouchableOpacity
activeOpacity={0.8}
onPress={this.onClick}
/>
)
}
}
You don't need to pass the message prop because you can access it anywhere in the component.
Just supply a function in the onPress prop. And in that function, just access the message prop of the component.
class Home extends Component {
onCardPress = (message) => {
alert(message)
}
render() {
return (
<View>
<Card
onCardPress={this.onCardPress}
message="Hello world!"
/>
</View>
)
}
}
class Card extends Component {
onClick = () => {
const { message, onCardPress } = this.props;
onCardPress(message);
};
render() {
return (
<TouchableOpacity
activeOpacity={0.8}
onPress={this.onClick}
/>
)
}
}

React Native binding functions over .map()

So I am having some trouble combining concepts of .map() and function binding. I am using .map() in the same way ngFor is used in angular, to place a custom button component on the page for every item in a user's account.
Here is some example code:
class MyButton extends Component {
constructor(props) {
super();
this.state = {
progress: 0
}
}
render() {
return(
<TouchableWithoutFeedback onPress={this.pressFunction}>
(...more code inside)
</TouchableWithoutFeedback>
)
}
pressFunction = () => {
(animate progress from 0 to 1 for some animation)
}
}
/////////////////////////////////////////////////////////////////
class Parent extends Component {
render() {
return(
{
this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton data={obj} />
</View>
)
})
}
)
}
}
So in the Parent Component, multiple MyButtons are rendered properly, each according to the passed object from the array. However, when any button is pressed, all of the pressFunctions for all MyButtons fire.
My question is I guess, how do I ensure that each pressFunction of each MyButton is bound only to the specific instance of the MyButton? I am having trouble with the scope here.
My understanding is that
functionName = () => {}
should properly bind the function to the instance, but I have tried the older ways as well with the same result.
I solved this by creating a dynamic ref on each object mapped to a MyButton, using a unique property of each obj in the array:
this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton ref={obj.name} data={obj} />
</View>
)
})
Still don't know why my it didn't bind uniquely without a ref
You should pass onPress as a props. Below is the updated code
class MyButton extends Component {
constructor(props) {
super();
this.state = {
progress: 0
}
}
render() {
return(
<TouchableWithoutFeedback onPress={this.props.onPress}>
(...more code inside)
</TouchableWithoutFeedback>
)
}
}
/////////////////////////////////////////////////////////////////
class Parent extends Component {
pressFunction = () => {
(animate progress from 0 to 1 for some animation)
}
render() {
return this.props.data.array.map(obj => {
return(
<View style={someStyle}>
<MyButton
data={obj}
onPress={this.pressFunction}
/>
</View>
)
})
}
}

React Native - TextInput - How to use value & defaultValue together

I got the following Component and I want to init TextInput with defaultValue and then when user type update the value of it.
How do I do that?
Here what I've tried - but this way TextInput is always empty on initialization.
class Note extends Component {
state = {
text: ""
};
render() {
const {onChange} = this.props;
return (
<TextInput
onChangeText={(text) => {
this.setState({text});
onChange(text);
}
value={this.state.text}
defaultValue={this.props.text}
/>
);
} }
"react": "^16.4.1"
"react-native": "^0.55.4",
Finally solved it,
The key is the following - "value" has preceding over "defaultValue" unless "value" is undefined!
So, Init this.state.text = undefined, this way defaultValue can be initialized with this.props.text.
class Note extends Component {
state = {
text: undefined
};
render() {
const {onChange} = this.props;
return (
<View>
<TextInput
onChangeText={(text) => {
this.setState({text});
onChange(text);
}
value={this.state.text}
defaultValue={this.props.text}
/>
</View>
);
}
}
I found this a bit more clean than #anilSidhu solution.
You can set default value in state itself like following:
class Note extends Component {
state = {
text: this.props.text
};
render() {
const {onChange} = this.props;
return (
<TextInput
onChangeText={(text) => {
this.setState({text});
onChange(text);
}
value={this.state.text}
/>
);
} }
class Note extends Component {
state = {
text: undefined
};
componentDidMount() {
this.setState({ text: this.props.text })
}
render() {
return (
<TextInput
onChange={(text) => {
this.setState({ text: text.target.value });
}}
value={this.state.text}
/>
);
}
}
It should work for you and if you are still facing the issue let me know please
Basically, when you're having both value and defaultValue props, always value prop will take precedence and thus defaultValue won't be reflected.
Sometimes if you are showing number type to default value it doesn't work. you must convert to string type as follows:
defaultValue(String(this.props.text)}
For someone having trouble with this problem. I've experienced it. i expect my number Value to be displayed on Textinput. But placeholders keep showing.
The solution is your Value must be String.
So i convert my Number to String use toString() method.
Hope this helps.

Resources