React : State and props on the same parameter - reactjs

I'm a junior developer.
I use Textfield of material ui, but i have a problem. I get the value by a property, and it works ! however i can't edit the textfield, so i would want to use the onChange parameter, this is my code :
<TextField ref="docLibelle" value={this.props.lastuploadfile.content} onChange={this._handleTextFieldChange}
And my function :
_handleTextFieldChange = (e:any) => {
this.setState({
showReferenceIsRequired : false,
libelDoc: e.target.value
});
}
And I try that :
<TextField ref="docLibelle" value={this.state.libelDoc&& this.props.lastuploadfile.content} onChange={this._handleTextFieldChange}
But it doesn't work .. How can i get the value by the property and edit also the textfield ?
Thank you for yours answers !

I think the solution is pretty simple. Since you want to be able to change the textField value and also initialize it with a value you can just setState with props in your componentDidMount method
componentDidMount(){
this.setState({libelDoc: this.props.lastuploadfile.content})
}
and use it like'
<TextField ref="docLibelle" value={this.state.libelDoc} onChange={this._handleTextFieldChange}

Issue is, in value property you are using the props value and inside the onChange method updating the state value, because of that your textfield is read only.
Solutions:
1. Pass a function from parent component and onChange of textfield use that function to update the parent value, it will work, like this:
In Child component:
<TextField ref="docLibelle" value={this.props.lastuploadfile.content} onChange={this._handleTextFieldChange}/>
_handleTextFieldChange = (e:any) => {
this.setState({
showReferenceIsRequired : false,
});
this.props.updateValue(e.target.value);
}
In Parent component:
updateValue(value){
let = this.state.lastuploadfile;
lastuploadfile.content = value;
this.setState({lastuploadfile})
}
2. Store the props value in state variable and use that variable in value property of textfield.
Store the initial value of textfield in state variable:
constructor(props){
super(props);
this.state = {libelDoc: props.lastuploadfile.content}
}
Use that variable in value property in textfield:
<TextField ref="docLibelle" value={this.state.libelDoc} onChange={this._handleTextFieldChange}
Update that state variable in onChange method:
_handleTextFieldChange = (event, value) => {
this.setState({
showReferenceIsRequired : false,
libelDoc: value
});
}

Related

Setting the defultValue of TextField component of Material UI in React

I am developing a React JS application. What I am doing now is I am fetching data asynchronously from the server and render the values in the TextField. I know how to do it and my approach is working as well. But, I just do not like my current approach.
This is the working approach
class TestComponent extends React.Component {
constructor(props)
{
super(props);
this.fetchName = this.fetchName.bind(this);
this.handleChange = this.handleChange.bind(this);
this.state = {
name : ''
}
}
fetchName()
{
//get the name asynchronously from the server. I am using Axios
this.setState({ name : nameValueFromTheServer })
}
handleChange(e)
{
this.setState({ name : e.target.value })
}
render()
{
return (
<MuiThemeProvider>
<div>
<TextField onChange={this.handleChange} label="Name" value={this.state.name} />
</div>
</MuiThemeProvider>
)
}
}
The thing I do not like about above approach is that I have to implement handleChange method to retrieve the value of the input value. If I do not implement it, I cannot change the name input value because the state value is not changed. To retrieve a simple input value, I have to write extra lines of code. In jQuery, I just retrieve the input value like this, $(selector).val(). Without implementing the handleChange method, I can use the ref like this.
<TextField inputRedf={(input) => this.tfName = input } label="Name" />
Then I retrieve the value dynamically like this.
this.tfName.value
The problem with using the reference is setting the default value which is fetched asynchronously from the server.
I can set the default value like this to the TextField
<TextField inputRedf={(input) => this.tfName = input } defaultValue={this.state.name} label="Name" />
Pay attention to the defaultValue attribute in the above code. When I set the value using defaultValue, the initial value of the name state will be set to the text field. But we can still change the input value of the name typing in from the UI even if we do not implement the handleChange event. But the problem is that I am getting the data asynchronously and setting the this.state.name dynamically.
So in the component constructor, the name state is empty. Then I set it in the callback of the asynchronous call. But the defaultValue can be set only once. So the input field is always showing empty. What I like to know is, how can I set the defaultValue of the TextField dynamically? The reason I am using ref is that I do not want to implement the onChange event as well to track state the reset the input value. If I could set the defaultValue dynamically, I will just the value dynamically in the callback of the asynchronous call. What is the best solution to simplify this scenario?
You don't need default value actually. If you want to avoid using onChange handler you can imperatively set input value in async callback:
class TestComponent extends React.Component {
constructor(props) {
super(props);
this.fetchName = this.fetchName.bind(this);
this.handleChange = this.handleChange.bind(this);
}
fetchName() {
if(this.tfName.value == '') {
// only update if user have not changed the input value.
this.tfName.value = nameValueFromTheServer;
}
}
render() {
return (
<MuiThemeProvider>
<div>
<TextField
inputRef={(input) => this.tfName = input }
label="Name"/>
</div>
</MuiThemeProvider>
);
}
}

react-select does not clear value when redux-form is reset

I have a stateless React function to render a react-select Select to a form. Everything else works nicely with redux-form except when redux-form is reset. I need to reset the form manually after successful post.
onChange and onBlur change the redux-form value correctly when Select has a value change. When I reset the redux-form, the redux-form value is cleared but the Select will have the old value.
function SelectInput(props) {
const { input, options, label } = props;
const { onChange, onBlur } = input;
const handleChange = ({ value }) => {
onChange(value);
};
const handleBlur = ({ value }) => {
onBlur(value);
};
return (
<FormField {...props}>
<Select placeholder={label} options={options} onChange={handleChange} onBlur={handleBlur} />
</FormField>
);
}
I converted the SelectInput to React.PureComponent, and added the value as a state inside the component and looked for when the Component received new props:
constructor(props) {
super(props);
this.state = {value: ''}
}
componentWillReceiveProps(nextProps){
this.setState({value: nextprops.input.value})
}
<Select value={this.state.value} placeholder={label} options={options} onChange={handleChange} onBlur={handleBlur} />
With this Select was not able to show the value at all.
The problem is that how I can update the Select to show empty value when redux-form that this field is part of is reset? Redux-form resets the value corretly inside the redux state and if I try to submit the form, validation notices that that Select has empty value. The Select will however display the old value so that user thinks that there is a value selected.
Reset is done by dispatching reset in the actual redux-form component. Redux devtools show that fields are reset and the redux state is cleared from all the value, Select component just won't update the DISPLAYED value to empty.
const afterSubmit = (result, dispatch) =>
dispatch(reset('datainputform'));
export default reduxForm({
form: 'datainputform',
onSubmitSuccess: afterSubmit,
})(DataInputForm);
Versions I use:
react-select#v2.0.0-beta.6
redux-form#7.3.0
You can also set a key at the form level itself. The key will take a unique value that you can store in the component state. This unique value will be updated every time reset is hit.
state = {
unique_key: ''
}
// this is the onClick handler for reset button on the form
onResetForm = () => {
reset_val = Date.now();
this.props.reset();
this.setState({unique_key: reset_val});
}
<Form actions={action_func}, key={this.state.unique_key}/>
Now whenever reset is clicked, the handler will update the unique_key. This will result in re-rendering the Form with the default values. The handler also calls the form reset function to clear the redux.
Got it working. Problem was handling the Select null value. Changed stateless function to PureComponent, added the value to state.
constructor(props) {
super(props);
this.state = { value: '' };
}
Redux-form changes the react-select value by sending new props. So added
componentWillReceiveProps(nextProps) {
if (nextProps.input.value === '') {
this.setState({ value: '' });
}
}
Added setState to handleChange:
handleChange = (data) => {
const value = data === null ? '' : data;
this.setState({ value });
this.props.input.onChange(data.value);
};
And then added the value prop.
<Select value={this.state.value}...

reduxForm - initialValues did not apply after update

I use Redux Form Version 6.8.0.
I have a form component which get's it's "initialValues" via a "mapStateToProps" function. On the first render everything works quite fine.
Following my form config:
const CategoryChangeForm = reduxForm({
form: 'change-category',
validate: newCategoryValidate,
enableReinitialize: true
})(CategoryChange);
When i change the Field "category" and the update succeed, i receive the new updated value from firebase.
I pass this updated value via the mentioned "mapStateToProps" function to the "initialValues":
function mapStateToProps(state, ownProps) {
return {
initialValues: { category: state.categories[ownProps.id].name, id: ownProps.id }
};
}
I expected that the new Value would be applied to the "category"-Field Component. But it doesn't get the updated value.
The config of my "Field" Components:
const fieldProps = {
category: {
name: 'category',
type: 'text',
placeholder: 'Bezeichnung',
component: InputField
},
hidden: {
name: 'id',
type: 'hidden',
component: 'input'
}
};
and here is my Form Component:
export const CategoryChange = props => {
const {
color,
message,
handleSubmit,
stateComponent
} = props;
console.log("Props: ", props);
return (
<span>
<Subline color={ color } marginTop={ 70 } marginBottom={ 30 } align="center">{ message }</Subline>
<form>
<Field { ...fieldProps.category } />
<Field { ...fieldProps.hidden } />
<Button onClick={ handleSubmit(changeCategory.bind(stateComponent)) }>Ändern</Button>
<Button marginBottom={ 5 } marginTop={ 10 }>Löschen</Button>
</form>
</span>
);
}
I can observe that after an update, my form component rerenders 2 times. First time its prop "initialized" is set to "true". But the second time its set to "false".
The second render occurs due to a stateChange of the hoc component which wrapped my form component. The "setState" for the hoc is triggered when the update was successful and show an appropriate message to the user.
But cause of the second render the form component did not initialize.
If you need any more code to see, let me know.
Hope someone has a hint to solve this problem...
According to the docs:
By default, you may only initialize a form component once via
initialValues. There are two methods to reinitialize the form
component with new "pristine" values:
Pass a enableReinitialize prop or reduxForm() config parameter set to
true to allow the form the reinitialize with new "pristine" values
every time the initialValues prop changes. To keep dirty form values
when it reinitializes, you can set keepDirtyOnReinitialize to true. By
default, reinitializing the form replaces all dirty values with
"pristine" values.
Dispatch the INITIALIZE action (using the action creator provided by
redux-form).
You can change CategoryChangeForm from function to class and call initialize action from redux-forms in the componentWillReceiveProps method.
import {initialize} from 'redux-form'
CategoryChangeForm extends Component {
...
componentWillReceiveProps(nextProps) {
// check the props and call initialize when needed
}
}
mapDispatchToProps = dispatch => ({
initialize: (data) => initialize('change-category', data)
})

How to create a controlled Fabric UI TextField component?

I've been trying to code a controlled TextField component in the standard way just like in React docs:
handleChange(event) {
this.setState({
text: event.target.value
});
}
<TextField label='Enter Text' value={this.state.text} onChange={this.handleChange}/>
The code above is what I've been using, but it seems that it doesn't change the state of the react component, because in the same form if I change a controlled checkbox, it resets the textfield to be empty. If I use a standard html input element it works just as expected and doesn't clear the field.
What am I doing wrong here? Shouldn't TextField work the same way as a text type input?
From the docs, onChange is not a property. Use onChanged instead. Note that the return value is the textfield's value, not an event.
According to this example:
handleChange(value) {
this.setState({
text: value
});
}
I do not know what you want to do
but ... If what you need is to pass the input value to a text label, you can do it this way:
First you must declare an interface outside of your class
interface myState {
value1: string;
}
you must include your Interface in the class.
class TextFieldControlledExample extends React.Component<{}, myState> {...}
I suppose that for TypeScript themes you must publicly declare the interface of which you are using.
public state: myState = { value1: ''};
you must declare a function within the render to assign the value of the state
public render() {
const { value1 } = this.state;
in this way you assign the value of your inputs. but to update it you have to create a function and call it on the onChange
<TextField
label="Enter Text"
value={this.state.value1}
onChange={this._onChange}
styles={{ fieldGroup: { width: 300 } }}
/>
<Text variant='xxLarge' nowrap block>
{value1}
</Text>
to assign the input value to the state you have declared using setState. must do a function.
private _onChange = (ev: React.FormEvent<HTMLInputElement>, newValue?: string) => {
this.setState({ value1: newValue || '' });
};
You can see the example working here
https://codepen.io/jasp402/pen/EBWBgO

How to get value datapicker in react toobox custom?

How can I get the value of datapicker in react toobox?
I am using custom components.
I am using 2 components first one is called InputDateCustom.js with the code below:
import DatePicker from 'react-toolbox/lib/date_picker/DatePicker';
import React, { Component } from 'react';
const datetime = new Date(2015, 10, 16);
datetime.setHours(17);
datetime.setMinutes(28);
export default class InputDateCustomizado extends Component{
state = {date2: datetime};
handleChange = (item, value) => {
console.log(item+" - "+value)
this.setState({...this.state, [item]: value});
};
render() {
return (
<div>
<DatePicker
label={this.props.label}
locale={localeExample}
name={this.props.name}
required={this.props.required}
onChange={this.handleChange.bind(this, 'date1')}
value={this.state.date1}
/>
</div>
);
}
}
Another component is called Cadastro.js that contains the following logic:
constructor(props) {
super(props);
this.state = {msg: '', fim_vigencia:'', nome:''}
this.setNome = this.setNome.bind(this)
this.setFimVigencia = this.setFimVigencia.bind(this)
}
setFimVigencia(evento){
console.log("date")
this.setState({fim_vigencia:evento.target.value});
}
InputDateCustomizado
id="fim_vigencia"
label="Fim"
name="fim_vigencia"
value = {this.state.fim_vigencia}
onSubmit = {this.setFimVigencia}
/>
Get the value in an onChange event or using the value prop. Doc examples: http://react-toolbox.com/#/components/date_picker
<DatePicker label='Birthdate' onChange={this.handleChange.bind(this, 'date1')} value={this.state.date1} />
You can get access to the value in the handleChange event allowing you to update your state with the currently selected date.
EDIT: Ah okay I think I understand what you are asking now. You have wrapped DatePicker with your own component and now you want to get the DatePicker value through the Cadastro.js component.
You need to create a method in the Cadastro.js that accepts state changes from the InputDateCustomizado component and then pass that function as a prop to the InputDateCustomizado component. In the InputDateCustomizado when the state changes, call the passed in function and it should update the state in the parent component. Then you will always have the datepicker value in the parent component.
It looks like you are almost there. You need to add an updateState function to the Cadastro.js component. In the InputDateCustomizado component handleChange event, you need to call this.props.updateState and pass in the new value.
In Cadastro.js
updateState = (data) => {
this.setState({
date: data.data //set your state here to the date
})
}
In InputDateCustomizado
handleChange = (item, value) => {
console.log(item+" - "+value)
this.setState({...this.state, [item]: value});
this.props.updateState(this.state);
};

Resources