How to update the state of child component from parent? - javascript

I am just getting started with React and not able to figure this out.
<Select>
<Search term={this.state.filename} />
</Select>
Select component is for selecting a file, I want to set the initial value of input text inside the Search component to be the filename.
Here is the Search component
<form onSubmit={this.handleSubmit}>
<input
type="search"
value={this.props.term}
onChange={this.handleChange}
/>
</form>
Now, whenever user tries to change the value of input from the initial value set by the parent, I set the state of the child with the new input value but this triggers re-render of the child which resets the input value. What is the correct way around this?
What I am currently thinking is if I assign the value of input like this value={this.props.term}
, then changing the state will trigger re-render of the child with the filename as the default value and user will be able to edit it.

Try have onChange on Search be delegated to a props so that your parent will be the one that sets the value when onChange is called on child.
onChange={this.props.onInputChange}

Here you are using value={this.props.term}, which makes the input a controlled component. The value here will always be same as this.props.term, which is the state from parent component. <Search term={this.state.filename} />
I guess what you really want to do here is change parent's state inside child component.
Then you should pass a function from parent component to child component. The function will change the state of parent component. You should define Something in parent component like these:
onChildInputChange(term) {
this.setState({term: term })
}
Then pass it to child component through props
<Select>
<Search term={this.state.filename} onChildInputChange={this.onChildInputChange} />
</Select>
so that in child component you can do this:
<form onSubmit={this.handleSubmit}>
<input
type="search"
value={this.props.term}
onChange={()=>{this.props.onChildInputChange()}}
/>
</form>

Related

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]}
/>

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} />

ReactJS Dynamically Replace Children

I have a fancy UI in which have a few 'panes' with dividers in between that let you change what each one does. Say I have two different components - a to-do list and a simple text editor. I want you to be able to change the component present in each pane to make a flexible UI. For example, I might want to change the pane on the left from a text editor to a to-do list. Assuming I have a parent element Pane, how could I replace one of its children with another?
<Pane>
<TextEditor /> /* I want to replace that with a <ToDoList /> when I press a button */
<SomeOtherComponentOnTheRight />
</Pane>
I've tried storing React.Children.toArray(this.props.children) in the <Pane />'s state (as this.state.currentChildren), and replacing the element there, but for some reason I can't find a way to get the index of <TextEditor /> in the <Pane />'s this.state.currentChildren because for some reason this.props.children does not preserve children's props, and so I can't transmit data through it.
Sorry if I've overcomplicated this, but I simply want to know how to change a component's children dynamically.
You could check the state in your JSX to change what is displayed such as:
<Pane>
{ this.state.showEditor ? <TextEditor/> : <ToDoList /> }
<SomeOtherComponentOnTheRight />
</Pane>
Elsewhere in your code you would have some button that invokes an onClick event handler that would set the state of 'showEditor' to true/false depending on the previous state.
You can store the selected components in an array or object, then assign the selected component to a variable (just make sure it starts with an uppercase letter) and then use it as a component:
const routes = {
a: TextEditor,
b: ToDoList
};
const ChosenComponent = routes['a']; // select your component and store in variable
return (
<Pane>
<ChosenComponent />
<SomeOtherComponentOnTheRight /> {/* render selected variable as component */}
</Pane>
);

How to include a text input in a React component with its value specified?

I need to include a text input in a React component, with its initial value passed from the component's props:
<input value={this.props.value} type='text'/>
But the input is not editable, and React complains:
Warning: Failed form propType: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field.
So I add a onChange event handler:
<input value={this.props.value} type='text' onChange={this.valueChanged} />
What should I do in the valueChanged handler to update the input value? Do I have to use state?
Have a look at the documentation on forms, specifically controlled components.
Your valueChanged() method, where the change event is handled, would do something like this:
valueChanged(event) {
this.setState({
value: event.target.value //set this.state.value to the input's value
});
}
That means that yes, your input value would need to use state (this.state.value.) If you want this.state.value to be populated from this.props.value, you could do something like this in the constructor:
constructor(props) {
super(props);
this.state = {
value: props.value //passed prop as initial value
}
this.valueChanged = this.valueChanged.bind(this);
}
The above will initially set this.state.value to the passed prop value's value. Then apply the value from state and the onChange handler to your <input>:
<input value={this.state.value} type="text" onChange={this.valueChanged} />
Since this.state.value is the current input value, and is updated every time that value is changed, it becomes input-able as expected.
Here's a fiddle (thanks, Andrew): http://jsfiddle.net/ow99x7d5/2

What is the purpose of passing props to a React search bar?

I'm learning to Think in React, but don't understand why the SearchBar in the example needs to have value={this.props.filterText} and checked={this.props.inStockOnly}, the jsFiddle still works without them and it doesn't make sense for props to be passed to the SearchBar as the Search is the one handling user input and making changes to the state. The user input will be reflected in the value of the input without it being set to this.props.filterText so why is it there?
var SearchBar = React.createClass({
handleChange: function() {
this.props.onUserInput(
this.refs.filterTextInput.value,
this.refs.inStockOnlyInput.checked
);
},
render: function() {
return (
<form>
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
<p>
<input
type="checkbox"
checked={this.props.inStockOnly}
ref="inStockOnlyInput"
onChange={this.handleChange}
/>
{' '}
Only show products in stock
</p>
</form>
);
}
});
React has concept of controlled components. A controlled component means its value is set by state (And not the other way around i.e. State being set by value of component).
Consider the following example:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {term : ''};
}
render() {
return (
<div>
<input value={this.state.term} onChange = {event => this.setState({term : event.target.value}) }/>
</div>
);
}
}
In above example <SearchBar /> is a Controlled Component.
Following will be sequence of events:
You type 'abc' in input field.
At this time value of input field does not change. Rather the State of component is changing because of our code in onChange Event.
As the state of component changes, the component is rendered again. And now the value of component becomes 'abc'.
This concept becomes more important when we use redux, Actions etc.
Because you will be needing the inputted value from the search bar to the upper component. For instance, if you need to filter a collection based on the given value (through search bar), then the filtering will happen on the upper component, not on the search bar. Search bar is only for the input. We put the value of the search bar from the props to make sure that the values are aligned.
The example here depicts the use of controlled input from the parent component. As you see
<input
type="text"
placeholder="Search..."
value={this.props.filterText}
ref="filterTextInput"
onChange={this.handleChange}
/>
Here the value of input box is set to {this.props.value} and in the handlechange function you are the onUserInput function which you check is again passed as a prop to the Searchbar. This calls the handleUserInput function ni the FilterableProductTable component and it sets the states filterText, inStockOnly and only these are passed as props to the Searchbar component. So although you can do without it, but controlled input is the way to go in most cases since we are accepting the value provided by the user and updating the value prop of the <input> component. This pattern makes it easy to implement interfaces that respond to or validate user interactions. i.e. if you want to validate an input field or put restrictions on the input value its easier to do with controlled input

Categories

Resources