React Checkbox Depends on Parent State - reactjs

In my parent component, I have a regular component that renders checked based off state and it can call a function:
<input
name='shiftOne'
type='checkbox'
onChange={() => this.onCheck('shiftOne')}
checked={this.state.shiftBools['shiftOne']}
/>
This works fine except for a warning in the console saying that I am switching from controlling and uncontrolling, but it doesn't break anything.
Trying to do the React way, I seperate this Checkbox out into it's function:
function Checkbox (props) {
return (
<div>
<label>
<input
type='checkbox'
name={props.name}
checked={props.checked}
onChange={() => props.handleCheckChange(props.name)}
/>
{props.text}
</label>
</div>
)
}
export default Checkbox
And then I render it in my Root App Component:
<Checkbox
checked={this.state.shiftBools.shiftOne}
name={'shiftOne'}
onChange={() => this.handleCheckChange('shiftOne')}
text={shiftOne[0] + ' ' + shiftTwo[1]}
/>
When I use the Checkbox functional component, it's on change doesn't work, it just always stays checked. Also, it doesn't even call the function in the onChange. I tried to console.log inside it and it's not called:
handleCheckChange = () => {
console.log(1)
this.setState({
shiftBools: {
...this.state.shiftBools,
shiftOne: this.state.shiftOne
}
})
}
I am trying to think more in React and just using the input in the parent class works fine, I'm just not sure why the functional component isn't working. All the data is in my parent state and whether the checkbox is checked or not depends on the data I have in that state.
* EDIT *
I changed the functional component to a Class component:
class Checkbox extends Component {
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
}
handler() {
this.props.onCheck(this.props.name);
}
render() {
return (
<label>
<input
type="checkbox"
name={this.props.name}
checked={this.props.checked}
onChange={this.handler}
/>
{this.props.text}
</label>
);
}
}
Now I deal with the parent function through a handler function. I also binded the parent function, as I wasn't before:
this.onCheck = this.onCheck.bind(this);
Now my checkbox is rendered in the parent function like so:
<Checkbox
name={"shiftOne"}
checked={this.state.shiftBools.shiftOne}
onCheck={this.onCheck}
/>
This post helped me: How do I define methods in stateless components?
although my question was a little vague. Thanks for all your help.

You need to change the way you are calling onChange handler
Change
onChange={() => props.handleCheckChange(props.name)}
To
onChange={props.handleCheckChange(props.name)}
also, change the way of passing handler down has props to Checkbox component
<Checkbox
checked={this.state.shiftBools.shiftOne}
name={'shiftOne'}
onChange={this.handleCheckChange('shiftOne')}
text={shiftOne[0] + ' ' + shiftTwo[1]}
/>

Related

React Send child input data to update parent state

Setup: I have set up a two react components in a parent child relationship. The parent has a state that can be changed by press of a button on parent itself.
Expected behaviour: In the child, I have an input field and I want the state to change to the value I send in the input field on the press of the submit button. I have set up the parent and the child as follows:
What I have tried: I going through this answer and this youtube video but I guess I am not smart enough to make sense of it.
This is what my code looks like
Parent:
class App extends Component {
state = {
value:"someValue"
};
changeValue = (value) => {
this.setState({
value
})
}
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={()=>this.changeValue("valueFromParentComponent")}>Press to change value from parent component</button>
<br/><br/>
<Child getChildInputOnSubmit={()=>this.changeValue()} />
</div>
);
}
}
And this is what the child looks like
Child:
class Child extends Component {
state = {
}
sendChildData = (childInputValue) => {
console.group("This is the data from the input of the child component")
console.log("==============")
console.log(childInputValue)
console.log("==============")
}
render() {
return (
<div>
This is the child component
<br /><br />
<form>
<input type="text" placeholder="Some placeholder"></input>
<button onSubmit={this.sendChildData()} type="submit">Send child's input to parent</button>
</form>
</div>);
}
}
The React behaviour encourages to implement an inverse data flow inside a component hierarchy. Meaning that the child components can receive parent methods through props, this methods will work as callbacks, allowing to receive data, trigger behaviours, update his state and more.
I attach a StackBlitz example, showing how this concept would work in your setup https://stackblitz.com/edit/react-jsv5jo
Edit: Here a few extra tips applied on the example:
To work with inputs on React, a common setup consists on listen the onChange event to receive new data and update the component state. Then, this state is used in the value attribute to update the input content on DOM.
Listen the onSubmit event on the form tag instead on submit button, and remember to add some logic to avoid reloading.
Another good practice on React components is initialize your state object inside the Constructor (In case to be working with a Class Component) and write methods to avoid bloat the render one (Be sure to bind the extra methods on your constructor to avoid invocation problems)
Callbacks are used to pass data from Child component to Parent component in React.
We wright function in Parent component that will receive value and pass this function to child component through Props.
class Parent extends Component {
state = {
value: 'someValue'
};
changeValue = value => {
this.setState({
value
});
};
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={() => this.changeValue('valueFromParentComponent')}>
Press to change value from parent component
</button>
<br></br>
<Child getChildInputOnSubmit={this.changeValue} />
</div>
);
}
}
Now in Child component we call Parents function that we passed in props and send value.
class Child extends Component {
constructor(props) {
super(props);
this.state = {
Childvalue: ''
};
}
handleChange = event => {
event.preventDefault();
this.setState({ Childvalue: event.target.value });
};
sendToParent = () => {
//here calling Parents changeValue
this.props.getChildInputOnSubmit(this.state.Childvalue);
};
render() {
return (
<div>
This is the child Component
<br></br>
<form action='#' onSubmit={this.sendToParent}>
<input
type='text'
placeholder='Some placeholder'
value={this.state.Childvalue}
onChange={this.handleChange}
></input>
<button type='submit'>Send child's input to parent</button>
</form>
</div>
);
}
}

Value not updating inside a ReactJS function

I have a ReactJs function that displays a simple dialogue box, and is intended to update a value for the parent component. The function looks like this:
export function MyDialogue(props: IMyProps) {
var myValue = 0;
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={myValue} />
<button onClick={() => props.updateFunc(myValue)}>Update</button>
</div>
);
}
I've tried several variations of this; for example, passing in props.myValue, and even changing the function to a class and passing this.state.myValue in. In all but this example, myValue remains as it was in the parent class, and in this version, always 0.
updateFunc simply calls setState on the parent class, and having traced through it, it never gets called with the changed value.
I've seen some documentation that says to essentially handle the onChange event - is this the only way to make this work, or is there a way to implement data binding in React?
Just bind back your input to the parent's state via props.value;
MyDialogue.js
export function MyDialogue(props: IMyProps) {
return (
<div style={style}>
...
<input type="text" value={props.value} />
...
</div>
);
}
Parent.js
....
render(){
const { dialogueValue } = this.state;
return <MyDialuge value={dialogueValue} updateFunc={this.handleUpdate} />
}
You are using uncontrolled input because You are not keeping value of input inside state.
Solution is
With uncontrolled:
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.input = React.createRef();
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" ref={this.input} />
<button onClick={() => props.updateFunc(this.input.current.value)}>Update</button>
</div>
);
}
With controlled:
Maintain myValue state in parent and pass it to child.
and on change on input event call a function of parent which change myValue using setState,
Maintain myValye state inside MyDialogue and onClick pass it to parent.
You need to change this component to a stateful component
then do a two-way binding for your textbox and have it talk to local state and then use that state value to update parent component.
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.state = {
myValue: 0
}
}
onChangeHandler = (event:any) =>{
this.setState({myValue:event.target.value});
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={this.state.myValue} onChange={this.onChangeHandler}/>
<button onClick={() => props.updateFunc(this.state.myValue)}>Update</button>
</div>
);
}

How to pass a value to my parent React component from input type?

I have this in my parent TodoList component:
state = {
checkedIds: []
}
_handleSelectedTodo = (e) => {
e.preventDefault();
this.setState({checkedIds: [...this.state.checkedIds, e.value]});
}
the _handleSelectedTodo is passed as props to Todo component like this
<Todo
key={edge.node.id}
todo={edge.node}
viewer={this.props.viewer}
handleSelectedTodo={this._handleSelectedTodo}
/>
Now below is the code of my Todo component:
<li>
<input
checked={this.props.todo.complete}
className="toggle"
onChange={this.props.handleSelectedTodo.bind(null)}
type="checkbox"
value={this.props.todo.id}
/>
{this.props.todo.text+' - '+this.props.todo.complete}
I want to pass the value here to parent as e.target.value but I cannot succeed changing the state of my TodoList parent checkedIds. Help?
first it should be e.target.value instead of e.value
_handleSelectedTodo = (e) => {
// here add your logic for update the completed flag depending on the value of the id
this.setState({checkedIds: [...this.state.checkedIds, e.target.value]});
}
to pass the callback is without bind (since you already used arrow function in todoList)
<input
checked={this.props.todo.complete}
className="toggle"
onChange={this.props.handleSelectedTodo}
type="checkbox"
value={this.props.todo.id}
/>
additionally, I think you still need to handle when checkbox is unchecked (removed from the array)
https://codepen.io/kossel/pen/XRZPdK
Child
<input type="text" onChange={event => this.props.onInputChange(event.target.value)}/>
Parent
onInputChange(filter){
console.log(filter)
}
<child onInputChange ={this.onInputChange.bind(this)}/>

ReactJS: How-to set focus to input-element when it enters the DOM?

How to set focus to an input element when it enters the DOM?
Scenario
When a button is clicked the input element is displayed. How to set the focus to this element?
Code-Snippet
class Component extends React.Component{
constructor(props) {
super(props);
this.state = {
showInput: false
}
}
render() {
return (
<div>
<div onClick={() => {
this.setState({showInput: true});
ReactDOM.findDOMNode(this.refs.myInput).focus() // <- NOT WORKING
}}>
Show Input
</div>
{
(this.state.showInput) ? (
<input
type="text"
ref="myInput"
/>
) : ""
}
</div>
);
}
}
Calling ReactDOM.findDOMNode(this.refs.myInput).focus() after state change does not work. Also changing just the style or type property on state change does not work.
Assuming you only need one visible input on the page at a time to have autofocus Poh Zi How's suggestion of using the autofocus is probably the simplest.
<input type="text" autofocus/>
should do the trick, no JS needed!
In the componentDidMount and componentDidUpdate hooks do this:
ReactDOM.findDOMNode(this.refs.myInput).focus()
you should use ref
<input ref={(input) => { this.inputSearch = input; }} defaultValue="search ... " />
and use this code for focus
this.inputSearch.focus();
I had to define the variable as HTMLInputElement 1st...
private inputSearch: HTMLInputElement;
And then add this into the control:
ref={(input) => { this.inputSearch = input; }}
THEN I could get this to build/work:
this.inputSearch.focus();
From the docs:
"findDOMNode only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling findDOMNode() in render() on a component that has yet to be created) an exception will be thrown."
As mentioned by Piyush.kapoor, you need to place that incomponentDidMount and/or componentDidUpdate.

Reactjs - correct way of inherit props to first level children and nested children

In my case I try to create a simple Form Component - mostly for "testing" reactjs and work with it.
To do this I work with 2 Components. The first Component is the Parent, the "Form" Component. The second Component is the field of the form - for example a simple textfield. This is the markup it would look like:
<Form
schema={MyFormSchema}
>
<Input name="name" />
<Input name="age" />
</Form>
In MyFormSchema I have all information which I need for every Child of the type "Input". For this case I have done this in my "Form" Component:
Form.jsx
Form = React.createClass({
renderChildren() {
return React.Children.map(this.props.children, (child)=>{
if (child.type && child.type.prototype && child.type.prototype.constructor.displayName === 'Input') {
let additionalProps = {
fieldSchema: this.props.schema.pick(child.props.name),
onChange: this.onChange
};
return React.cloneElement(child, additionalProps);
}
return child;
});
},
render() {
return(
<form>
{this.renderChildren()}
</form>
);
}
});
What I am doing here is to "clone" every "input" child and add some new props depending on the schema.
So the first question is:
Is this really the correct war in reactJs ? When I am not "cloning" every element and adding new properties I have to add the property directly in my View, right ? Something like but I am trying to prevent this because all information I need I already have as a prop in my Form Schema.
After playing around with this I found out, that this.props.children only have the first level of children. But when I have nested my Children in my Form Component it will not work anymore that my Component is replacing the Input Component with the manipulated component.
Example:
<Form
schema={MyFormSchema}
>
<AnotherComponent>
<Input name="name" />
</AnotherComponent>
<Input name="age" />
</Form>
When I am doing it like I now doing it this code will not work anymore because in this.props.children I only have [AnotherComponent, Input[name=age]] and the Input[name=name] is missing. So I think the way I am doing it is the wrong way. But i am not sure.
So the main question is:
Like in my example: What is the correct way in ReactJs to inherit props (or what ever) to all children (also the nested one) - or is this not possible in the "react" way and I really have to pass all necessary props to all children ?
Edit:
When I am talking about "pass all necessary props to all children" I mean something like this:
<Form
schema={MyFormSchema}
>
<AnotherComponent>
<Input name="name" fieldSchema={this.getFieldSchema('name')} onChange={this.onChange} />
</AnotherComponent>
<Input name="age" fieldSchema={this.getFieldSchema('age')} onChange={this.onChange} />
</Form>
In this example I would pass all necessary props I want to add dynamically by the parent. In my example above the next problem would be: "this" would not work for the name input because of its parent AnotherComponent. So I would have to reference to the parent - of course: its possible, but I think it would be a ugly way.
There are three correct ways to deeply pass props:
1) Just actually pass them down the tree from each component to the next (this is the most readable (in terms of code logic), but can get unwieldy once you have too many props to pass and lots of levels in your tree.
Example:
import React from 'react';
var GrandParent = React.createClass({
render () {
return (
<Parent familyName={'componentFamily'} />
);
}
});
var Parent = React.createClass({
render () {
return (
<Child familyName={props.familyName} />
);
}
});
var Child = React.createClass({
render () {
return (
<p>{'Our family name is ' + props.familyName}</p>
);
}
});
2) Use a Flux-style store (I prefer Reflux, though Redux is all the rage right now) to keep a common state. All components can then access that store. For me at least, this is the current preferred method. It's clear and it keeps business logic out of the components.
Example (using Reflux):
import React from 'react';
import Reflux from 'reflux';
var MyStore = Reflux.createStore({
// This will be called in every component that connects to the store
getInitialState () {
return {
// Contents of MyFormSchema here
};
}
});
var Input = React.createClass({
propTypes: {
name: React.PropTypes.string.isRequired
},
mixins: [Reflux.connect(MyStore)],
render () {
// I don't know what MyFormSchema so I'm generalizing here, but lets pretend its a map that uses the name of each field a key and then has properties of that field within the map stored at the key/value
return (
<input type={this.state[name].type} name={this.props.name} value={this.state[name].type} />
);
}
});
3) Use React's context feature. As you'll see immediately from looking at the docs, this feature is still in development and is subject to possible change and even removal in future versions of React. So, while it is likely the easiest way to pass props down a tree of components, personally I'm staying away from it until it becomes more of a finalized feature.
I'm not going to write an example for this one since the docs make it very clear. However, make sure to scroll down on the doc page and take a look at Parent-child coupling, which is kind of what you're doing right now.
Another solution for you is that instead of having a single component that renders Form and its Inputs, why not just pass the prop to Form as you do currently, and then simply render the individual Input using Form's render().
You could use react-addons-clone-with-props package this way:
import React, { Component } from 'react';
import cloneWithProps from 'react-addons-clone-with-props';
// ...
class Form extends Component {
recursivelyMapChildren(children) {
return React.Children.map(children, child => {
if (!React.isValidElement(child)) {
return child;
}
return React.cloneElement(child, {
...child.props,
children: this.recursiveCloneChildren(child.props.children)
});
})
}
render() {
return (
<form>{this.recursivelyMapChildren(this.props.children)}</form>
);
}
}
What the code does:
Gets all the children components via predefined children prop (see docs).
Recursively maps the collection of children with React.Children.map method, applying a lambda function to each element.
Saves the mapped (i.e. updated, but not mutated!) children elements into mappedChildren constant.
Puts them within form DOM element.
It looks simple and it should be so.
But you have to keep in mind that React is great when your code is kept clean and transparent. When you explicitly pass props like
<Form
schema={MyFormSchema}
>
<Input
name="name"
schema={MyFormSchema} />
<Input
name="age"
schema={MyFormSchema} />
</Form>
there's way less things to get broken when you accidentally change the underlying logic.
Thankyou. Credits #Rishat Muhametshin
I have used the above to create a re-usable method.
This works beautifully:
utils/recursivelyMapChildren.jsx
const recursivelyMapChildren = (children, addedProperties) => {
return React.Children.map(children, child => {
if (!React.isValidElement(child)) {
return child;
}
return React.cloneElement(child, {
...child.props,
...addedProperties,
children: this.recursivelyMapChildren(child.props.children, addedProperties)
});
})
};
export default recursivelyMapChildren;
usecase:
Form.jsx
import recursivelyMapChildren from 'utils/recursivelyMapChildren';
class Form extends Component {
handleValidation(evt, name, strValidationType){
/* pass this method down to any nested level input field */
}
render(){
return (
<form>
{recursivelyMapChildren(this.props.children, {
handleValidation: this.handleValidation.bind(this)
})}
<input type="submit" value="submit" className="validation__submit"/>
</form>
)
}
}
export default Form
SomeExample.jsx
const SomeExample = () => {
return (
<Form>
<input type="hidden" name="_method" value="PUT"/>
<fieldset>
<legend>Personal details</legend>
<div className="formRow">
<InputText/> {/* This component will receive the method - handleValidation, so it is possible to update the state on the nested grand parent - form */}
</div>
<div className="formRow">
<InputText/>{/* This component will receive the method - handleValidation, so it is possible to update the state on the nested grand parent - form */}
</div>
</fieldset>
</Form>
)
}
export default SomeExample;
I have an alternate solution to pass props to nested children. The function createFormComponents takes the schema and produces an object of components that will receive props as usual but with the schema already provided. You could link the FormContainer in my example up to a store or use setState to handle changes to the schema over time and the children will update correctly.
The example's output is to the console to demonstrate that the props are received as expected.
function Form_(props) {
console.log('Form props', props)
return <div>{props.children}</div>
}
function Input_(props) {
console.log('Input props', props)
return <div />
}
function createFormComponents(schema) {
return {
Form: props => {
return Form_({ ...props, schema })
},
Input: props => {
return Input_({ ...props, schema })
},
}
}
const FormContainer = React.createClass({
render: function() {
const myFormSchema = { x: 0, y: 1, z: 2 }
const {
Form,
Input,
} = createFormComponents(myFormSchema)
return (
<Form>
<Input name="name" />
<Input name="age" />
</Form>
)
}
})
ReactDOM.render(
<FormContainer />,
document.getElementById('container')
)
Fiddle: Props Example

Resources