Which event to use for emitting change from inputs? - javascript

I have a React component that has many <TextInput> components, which are just simple wrappers around text <input> elements. Example:
<div>
<TextInput value={person.FirstName} ... />
<TextInput value={person.LastName} ... />
</div>
I also have some state represented by a person object. For example:
{
"FirstName": "Buster",
"LastName": "Posey"
}
Each <TextInput> component manages it's own internal state, which is the value of the text <input> at a given time.
When I click on a Save button, I want to make sure the person object has the most recent values from all of the <TextInput> components.
I can think of two ways to do this:
Events (onKeyDown, onChange, onBlur). An event inside the <TextInput> will create an action, it goes through the dispatcher, and the store updates the person object one field at a time.
Refs. I know this is an anti-pattern, but it really does seem so much simpler. I can iterate over refs when Save is clicked and pull out the state and fire an action.
What is the idiomatic way of doing this?

If it's just a simple wrapper around input, give it the same api as input, and don't have it manage internal state it doesn't need to.
render(){
var person = this.state.person;
return <div>
<TextInput value={person.FirstName} onChange={this.handleFirstNameChange} />
...
</div>
},
handleFirstNameChange(name){
this.setState({person: update(this.state.person, {
FirstName: {$set: name}
}});
}
update is React.addons.update, just as an example
And when save is clicked you send it out in an action. You can have a store for each piece of temporary data if you really need to, but it's almost always overkill if you don't persist it.

Related

ReactJS - update component (generated from a list) in the same div

It's a basic question but I searched for a guide without success...
I want to have a list of dropdowns and inputs and each dropdown will change the input next to it.
var list = [{ name: "foo1"}, {name: "foo2"}];
return (
{list.map( (name) => {
return (<div>
<dropdown data={someData}
onChange={(ev) => {
if(ev.value == 'clearIt')
<CHANGE THE NEAR INPUT VALUE>
}
}/>
<input value={name.name} />
</div>)
})});
I don't want to use DOM nor ref cause I understood that it's better to avoid it.
Any suggestions?
Or maybe the ref is the only option?
Thanks
So you can achieve this by doing the following steps:
Create a new component and move the dropdown and input to this new component.
Add state to your component by following this example:
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
Add an event listener onChange to the dropdown with an event handler which can update the state you created in the first step. (Remember to bind the handler in the constructor.
Add the new component within the div element of this example you gave and pass the relevant data you need to the new component you created.
This should allow you to update only the input next to the dropdown. Also it allows you to have different data for each dropdown you created.

Forkim's innerRef is updating every time a field in the form is changed

I am new with formik and I have a very annoying problem that I am stuck on with days. So basically I have a parent component in which I have a code like this:
const refs=[]
{data.map((v,i) =>
<Child formikRef={refs}}/> )}
And my child component uses formik:
...
<Formik
innerRef={i => props.formikRef.push(i)}
....../>
So my Child component is rendered a couple of times in my parent component, and I need to track the values of each in my parent component. To be more clear, when I click on button that is located in my parent component, I need to have the values from each (I need to pass data from child to parent component). That's why I am using innerRef. The problem is that I am using an array of refs to track values of each rendered , and a new value is added in the array every time I change a field in my form, so I have far more elements in my array than I should have. I think innderRef is triggered each time a change in a field is made, instead of only onSubmit. How I can solve this problem? Pls help.
You could try like below, Here we are passing index value to Child component to have Formik ref in the same place.
const refs=[]
{data.map((v,i) =>
<Child index={i} formikRef={refs}}/>
)}
<Formik
innerRef={props.formikRef[props.index]}
/>

"toggled" attribute not working (redux-form-material-ui)

I'm trying to use Toggle from redux-form-material-ui:
import { Toggle } from 'redux-form-material-ui'
It works ok updating the toggled value to the store on its onChange:
<Col xs='3'>
<h3 className="title-page">Parceiro</h3>
<Field name="possui-parceiro" component={Toggle} label="Possui parceiro?" />
</Col>
Problem is: I make a call to some API and I need to update the value of this toggled "programatically". Theoretically, I can use the toggled attribute as stated here, but this just doesn't work:
<Col xs='3'>
<h3 className="title-page">Parceiro</h3>
<Field name="possui-parceiro" component={Toggle} toggled={this.state.someBloodyState} label="Possui parceiro?" />
</Col>
Which leads me to believe that in this case redux-form is just on the way of the update / manipulation process, forcing me to somehow update the form on the store to toggle the value, and it looks messy to dispatch such action. Anyway, how do you proceed in such cases?
I would store the API result in the redux state, read it from your mapStateToProps and pass it to the component in the property initialValues setting enableReinitialize: true.
These 2 properties are the way of redux-form to change stuff programmatically "later on" after the form already rendered.
Otherwise , if you can fetch your data before even rendering the form, you can just use initialValues without enableReinitialize.
Another way is to use the change function provided by redux form
More info in the docs

Updating state in Reactjs?

I am trying to update my state in ReactJS. To do this I have an input field in a Reactjs class. The field is automatically filled in with data from a parent class. The field looks like this:
<input
onChange={e => this.props.store.addLego(e)}
name="piece"
value={this.props.row.original.piece}
/>
The addLego function is designed to update my state and is in a MobX store. It looks like this:
addLego = action("addLego", e => {
this[e.target.name] = e.target.value;
});
However, I can't actually edit the input field! Nothing changes in the field when I type! Thanks for your help!
If you set a value attribute to an <input> field that field becomes a controlled input. This means that whatever gets passed to value is rendered on the screen. In your case, if you are not updating this.props.row.original.piece the <input> field will never get a new value. I'll suggest to read this bit of React's documentation https://reactjs.org/docs/forms.html#controlled-components
It is basically suggesting to keep the new value somewhere (in the component's state for example) and set it back as a value to the field.
Follow this tutorial here will solve your problem. It's a good read too for handling single or multiple inputs
Basically, you'll need a state in the constructor
this.state = {value: ''};
Event handler to set the value every onchange
handleChange(event) {
this.setState({value: event.target.value});
}
And the setup for input
<input type="text" value={this.state.value} onChange={this.handleChange} />

Replacing child react component with another based on user intreaction or button click

I have created bootstrap modal component in react.
var carModal=<Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
<CarStructure callbackParent={this.showCarOptionsUpdate}/>
</Modal>
In car structure I have a form where based on button click I want to remove <CarStructure> child component from the modal carModal and update it with another component with different form structure. How can I replace <CarStructure> with another component having totally different user interface and options?
Remember that the job of a React component's render function is to describe how the component should look at any given point at time, so you don't "remove" or "change" pieces of the DOM so much as you describe when they should change themselves. So, you'll want to base the internal component of <Modal> on some sort of state (which may change throughout the life of the parent component). Something like this might do the trick:
var carModalBody;
if (this.state.something) {
var carModalBody = <CarStructure callbackParent={this.showCarOptionsUpdate} />;
} else {
var carModalBody = <SomeOtherComponent />;
}
var carModal = <Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
{carModalBody}
</Modal>

Categories

Resources