defaultValue of react not working in meteor - javascript

I am trying to figure this out, I don't know why this isn't working
<input type="text" id="first_name" name="first_name" className="form-control" defaultValue={this.props.user.first_name} required/>
but this works
<input type="text" id="first_name" name="first_name" className="form-control" value={this.props.user.first_name} required/>
the difference is value and defaultValue, if I use value the field becomes readonly and using defaultValue doesn't print any thing.
I am using react with meteor. I have tried logging this.props.user in render method before the return statement and it prints the object.

When you assign this.props.user.first_name to the value attribute it's not that the input field is becoming read-only, it's that you are never handling what happens when that value changes. React is simply re-rendering it with the value you directly assigned to it each time.
If you are looking to make the field editable + have the default user name value you should probably maintain and be aware of the state of the input.
So for example:
// Initialize some component state in either your constructor or getInitialState function
constructor(props){
super(props);
this.state = {userInput: this.props.user.first_name};
}
// Have a function that updates state when your input changes
onInputChange(event) {
this.setState({ userInput: event.target.value });
}
// Then set the value equal to your userInput state and add an onChange
// prop to the input tag in your render method.
render() {
return (
...
<input
type="text"
id="first_name"
name="first_name"
className="form-control"
value={this.state.userInput}
onChange={this.onInputChange.bind(this)} />
)
}
Then the value for the field initializes to the value it's being provided through this.props.user.first_name, while also remaining editable.
Edit:
As pointed out in the comments, while valid, this is actually an anti-pattern in React. Because the initial state of the child component is only called once, a change from a parent to the prop value of this.props.user.first_name will not cause any change in the state of the child. This is fine if the use case is to expressly set an initial value that you do not want or expect to change during the component life-cycle (though even then it's not a great pattern), but if you do expect the initial value to be mutable you have two options.
Option One: Bring the state up into the parent component, where it likely belongs. The child component should then receive and render any props that are sent it's way. Changes to the initial value are handled in the parent component state, props are treated as immutable, and everything stays in sync.
Option Two: If for whatever reason you both need to determine state from props and you also expect those props to change, you can make use of the componentWillReceiveProps(nextProps) life-cycle method to keep everything in sync. This will allow you to check this.props against nextProps and make any state changes if they are necessary:
componentWillReceiveProps(nextProps) {
if(nextProps.user.first_name !== this.props.user.first_name){
this.setState({
userInput: nextProps.user.first_name
});
}
}
Here's a link to the DOCS for further reference.

Related

Use parent component to pass initial value to child without relying on state ReactJS

I have a parent Component A that computes some initial value for his child Component B. Actually i compute the initial value in componentDidMount() of Component A and pass it to B through props:
<ComponentB initialValue={this.state.value} handleChange={this.handleChange}/>
And in component B i do
this.state = {value: this.props.initialValue}
After this, Component B should manage his state independently. But every time it's value change, i want it to update A's state but with less information.
In Component B:
const onChange = (event) => {
this.setState({value: event.target.value + "only in B"});
this.props.handleChange(this.state.value);
}
In ComponentA:
const handleChange = (value) => {
this.setState({value: value});
}
The problem is that A always has the last word and value in B doesn't keep the "only in b" suffix. A reset the value of B's state to his internal state value through the initialValue props when it renders again.
So basically, what i want to do is to inherit the initial value from A at first render, and then update A state when a change occurs in B without erasing B's state.
Hey even though you may do this better way if I understood correctly I think you can achieve what you want by just using:
this.props.value
on B Component:
<input defaultValue={this.props.value} onChange={this.onChange}/>
and then when you handle update just pass in event.target.value to parent (A component)
I'm not 100% sure if that's what you are asking but here's example:
https://codepen.io/pegla/pen/qBNxqBd?editors=1111
Any change in the parent component will trigger a re-render of the child component. I believe the best approach for your situation is after inheriting the initial value from A, set some local state variable to the B component to manage that state specifically so it's separate from A.

React.js: Should parent or component manage state?

I have a "Date input" component that contains a <input type="text">.
It's purpose is to allow users to type in a valid date (e.g., mm/dd/yyyy).
Once a user enters a valid date, the parent of the component should receive that date.
Based on this - I'm trying to figure out whether the component or the parent should manage state.
If I set it up so the parent manages state:
render() {
return (
<div>
<input type="text" value={this.props.value} onChange={this.props.handleChange} />
</div>
);
}
... this is no good, because the parent will be notified with every single change, and the prop will be set to all the "draft" values (e.g., "07/2") while the user is typing.
That suggests that I should set this up so that the component manages it's own state:
class InputDateWithLabel extends Component {
constructor(props) {
super(props);
this.state = {
value: formatDate(this.props.value) // formatDate() formats a date object into an 'mm/dd/yyyy' string
};
this.handleChange = this.handleChange.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}
handleChange(event) {
// use setState() to update this.state.value so the <input> shows what the user types
}
handleBlur(event) {
// if the user entered a valid date,
// convert the user's input to a date object,
// and communicate that to the parent. E.g.,:
this.props.onChange([new date]);
// Otherwise, handle the "error"
}
render() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} onBlur={this.handleBlur} />
);
}
}
This version works exactly the way I want it to, except for one more requirement...
Based on things that might happen elsewhere in my application, the parent may need to set the date in this component. However - now that the component is managing it's own state - when the parent changes props.value, my component will ignore it.
The React documents address this scenario here: You Probably Don't Need Derived State
But their solutions don't seem to apply:
One way to avoid the problems mentioned above is to remove state from our component entirely.
This is no good, because I don't want to make the parent responsible for validating the user's date input. My component should be self-contained, including the date validation, which means it needs to manage the "draft states" of the user's input.
Another alternative would be for our component to fully own the “draft” state. In that case, our component could still accept a prop for the initial value, but it would ignore subsequent changes to that prop
This is no good, because I need to retain the ability for the parent to change the value when appropriate.
The rest of the React documentation mentions a few other possibilities (getDerivedStateFromProps), but it goes to great lengths to stress that they're probably not correct. (Note the title of the article!)
This does not seem like an uncommon situation, so there must be a clear, simple, well-documented way to handle it, that's done the right "React-way". What is that?
Having a component manage it's own state doesn't seem that bad in your case, but you will need to add componentWillReceiveProps which adds another piece of code to manage.
componentWillReceiveProps(nextProps) {
this.setState({
value: formatDate(nextProps.value)
});
}

Dynamically add attributes in React render input

I have an input tag in render like this:
<input id="time" type="time">
and I need dynamimically add value attribute
How can I do this in React? Thanks in advance
Yes, you can do. e.g. props is an object which contains props or properties that you want to add based on some condition then you can something like
const props = { id: 'time', type: 'time' };
if (condition1) {
props.value = 'some value';
}
if(condition2) {
props.abc = 'some other value';
}
<input {...props} >
You should add an onchange attribute on the input which changes the state of your component. This will look something like this:
<input type="text" value={this.state.value} onChange={this.handleChange} />
The handleChange method should then look something like this:
handleChange = (event) => {
this.setState({value: event.target.value});
}
For more information check out the following article: https://reactjs.org/docs/forms.html
You would need to set the state of React. So...
this.setState({
myValue: newValue
})
Then, inside render:
<input id="time" type="time" value={this.state.myValue}>
This assumes you have your state setup with a constructor. Which is a whole other can of worms.
You shouldn't dynamically add or remove a "value" field. When you create a React input, it must be either "controlled" or "uncontrolled" through its whole lifespan. Changing it will make React yell a warning on the console.
React understads an input is meant to be uncontrolled if value is not present or undefined, so you need to at least set it to "" in order to achieve a controlled empty input.
"Controlled" means react controls its value. Ex: For the value to be changed, you'd need to notify react of the change (through onChange + setState) and then make it change its value;
"Uncontrolled" means react can't control the input's value, and you'd read and change the value through regular DOM ways (ex: input.value).
That being said, in order to dynamically change the presence of any element properties (props), you can use the "object spread" operator.
function render() {
const custom = { value: 2, color: randomColor() }
return <Element {...custom}/>
}
I guess you are rendering the tag within a render() function within a JSX expression (otherwise you would have added it through normal Javascript or JQuery).
Therefore the JSX expression will have something like:
<input id="time" type="time" value={yourValue}>
making sure that yourValue is in scope within the context of execution of your render() in your ReactComponent class or in the props. Alternatively it could be in the state.

Use Redux as an initial component state

I'm using Redux as an initial state in a component used to edit the name of a current selected item (containing these properties : "name", and "selected"). It's used as a local initial state, because I want to update the Redux global state only when I click on a save button (that I didn't implemented yet).
constructor(props) {
super(props)
this.state = {
item: this.props.item
}
}
My render function contains an editing name input :
<TextField
id={"name"}
value={this.state.item.name}
onChange={e => this.updateName(e.target.value)}
/>
The updateName() function is :
updateName = (value) => {
var newItem = this.state.item
newItem.name = value
this.setState({item: newItem})
}
Here, I can selected an item, the default's value of the input changes following the name of the item I selected (when I select an item, the state of Redux is updated, so is the state of the component and the text in the input). Everything is working as intented.
When I write into the input, the written text changes, but the action of selecting an item do not update the text of the input anymore (it should follow the name of the selected item from Redux, like before I entered text).
Is it because the reference to the this.props.item (and afterward the updates of Redux) is lost as soon as I update the component state with this.setState() ? But how can I correct this problem ?
Keep in mind that the constructor is called only once, while your input is a controlled component, commanded by your state.
What you need to do is to update your component state based on redux state so, to this in the componentWillReceiveProps method.
Please note: updating the state using a prop is considered an anti-pattern.

Having trouble with setting state to value of "Enter name" field

I have a simple TextInput for entering your name. I want to pass this to another scene. First, though, I want to save the value to the state of the current component. When I open up the debugger, I get undefined for every console.log(this.name) I have.
Here is my code:
constructor(props) {
super(props);
this.state = {
name: ''
};
}
<TextInput style={styles.inputName}
placeholder="Enter your name"
textAlign="center"
onChange={this.handleChange.bind(this)} />
handleChange(event) {
this.setState({
name: event.nativeEvent.text
});
console.log(this.name)
}
Do you know why I am always getting "undefined" as the value of name? What is the proper way to set the state equivalent to what is being typed?
Is a better approach to set state only after the submit button is pressed? If so how is that done?
You're attempting to access this.name, which is checking for a (likely nonexistent) name property on the component object in your case. You should be looking at this.state.name. However, even if you did attempt to log out the updated state in your event handler via this.state.name, you would probably still run into problems. From the React docs:
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value.
Finally, I would suggest extracting the name value from your event through event.target.value rather than going through the nativeEvent property.

Categories