I want to create a dynamic input component using props
This is App.js File
<TextBox type="text" style="singIn" placeholder="hi there" />
<TextBox type="password" style="singUp" />
This is TextBox.js File
import React, { Component } from 'react'
class TextBox extends Component {
constructor(props) {
super(props)
}
render() {
const {type, value, ...other} = this.props
return (
<div>
<input type={type} value={value} {...other} />
</div>
)
}
}
export default TextBox
You can use state to set value dynamically, Instead of props.
Or
You can use state to set the value to props. So that if you change the state value automatically props value also will change.
You're on the right track!
In TextBox, what you can do in your render() method is to pass on all of the props to <input> using the Object spread operator. This passes on all of the props as key value pairs. So, you can do:
<input {...this.props} />
That essentially does:
<input type={this props.type}
value={this.props.value}
placeholder={this props.placeholder}
// and so on for every single key-value pair you have in props
/>
But, there is a slight problem. If you pass style as a prop, it must be "a JavaScript object with camelCased properties". That is, you can't pass "signIn" or "signUp" (which are just strings) as a style. Perhaps what you meant to do is pass them as a class prop (meaning, set the CSS class of the input to "signIn" or "signUp").
Here is a code sandbox that demonstrates using the Object spread operator to pass all of the props on to the child input.
Related
So, I have a custom, configurable input component which is supposed to be used in few different forms. The "configuration" for the input filed is being handled by the parent components (validations, type of input field, etc.).
The problem is the event type. For example, in one of the forms, I need the event type on the input field to be onBlur and in another form - onKeyDown.
The question is: how can I pass the event type from the parent component which renders the custom input filed?
Disclaimer - I am new to React, quite new to programming and have been looking for a solution for a few days now to no avail.
First, define your component, that holds the <input /> (or function)
class MyClass extends Component {
render() {
// you can extract some of the props if you want to manipulate somehow. Everything else will be saved in rest
const { value, name, ...rest } = this.props;
return (
<input value={value} name={name} {...rest} />
)
}
}
Then, to that new component, you can add any props, that are available for <input/> tag, example:
class Test extends Component {
render() {
return (
<Fragment>
<MyClass value={5} name="Name" onBlur={this.onBlur} onFocus={this.onFocus} />
<MyClass value="Hello, world!" id='randomId' onChange={e => console.log(e.target.value)} />
</Fragment>
)
}
onBlur = e => {
console.log('Blur');
}
onFocus = e => {
console.log('Focus');
}
}
Now you have two different inputs - one is listening for onBlur and onFocus, the other one has id and listens for onChange.
I have a parent component and a child component as following.
Parent component:
constructor(){
this.refs = React.createRef();
}
setRef(ref) {
console.log(ref)
}
handleChange(e) {
console.log(e)
}
render() {
return(
<ChildComponent ref={this.setRef} handleChange={this.handleChange.bind(this)}/>
)
}
Child Component:
render() {
return(
<input type="text" ref={this.props.ref} onChange={this.props.handleChange.bind(this)} > </input>
)
}
What changes should I do to get the ref value inside the handleChange() function in parent component? Thanks in advance.
If I´m reading correctly you want to access the input element from the parent component?
You have to use another name for your prop as ref is a keyword prop which will automatically assign the component the given variable.
<ChildComponent inputRef={this.setRef} handleChange={this.handleChange.bind(this)}/>
class ChildComponent extends Component {
render() {
return(
<input type="text" ref={this.props.inputRef} onChange= {this.props.handleChange.bind(this)} > </input>
);
}
}
Based on how you want to access the ref you can either set this.refs directly to the prop or set it inside your setRef function.
// either `this.refs` and then usable through `this.refs.current`
<ChildComponent inputRef={this.refs} {...} />
// or `this.setRef` and assign it yourself
setRef = (ref) => {this.refs = ref;}
ref(as well as key btw) is very special prop. It is not accessible in child by this.props.ref.
Shortest way is to use different prop to pass ref forward and backward:
class Parent ...
render() {
...
<Child inputRef={this.inputRef} />
class Child
...
render() {
<input ref={this.props.inputRef} ...
It's most flexible since you may access different ref inside you child component(e.g. inputRef + scrollableContainerRef + popupRef)
But in some cases you want to compose new component for existing code base. Say <input>'s replacement. Sure, in this case you would avoid changing all <input ref={...} /> onto <MyInput refProp={...}>.
Here you may use React.forwardRef. It feels the best with functional components like
export Child = React.forwardRef((props, forwardedRef) => {
...
return ...
<input ref={forwardedRef} />
})
But for class-based component you would rather use ref-prop with different name:
class Child
...
render()
return
...
<input ref={this.props.forwardedRefName} />
export ChildWithForwardRef = React.forwardRef((props, ref) => <Child forwardedRefName={ref} {...props} />)
PS since you will consume what forwardRef returns rather initial component(Child) you may want to specify displayName for it. This way you may be able find it later say with enzyme's find() or easy recognize element in browser's React DevTools
ref work only on native dom element, to make ref work on user defined Component, you need this:
https://reactjs.org/docs/forwarding-refs.html
We have our own input components (like Checkbox, Textbox, or even CurrencyInput component)
We are now using Formik. So we replaced all <input... with <Field... in our components, eg.
const Checkbox = (props) => {
...
return (
<div className={myClass1}>
<Field type='checkbox' name={props.name} className={myClass2} ... />
<label ...>{props.label}</label>
</div>
)
};
Now the problem is, we can't have a standalone Checkbox outside a form anymore (eg. for an on-screen-only option). It will throw:
this.props.formik.registerField is not a function
We feel this is a dealbreaker. But before we ditch Formik and write our own form validation logics, I wonder if anyone else are having this dependency issue.
Is there really no way of rendering Formik Field outside Formik?
The Field component is what connects a form field to the Formik state. It uses context under the hood; Formik is the context provider and Field is the context consumer. Field is tied to Formik and has no use outside of it. For your use case where you want to render form fields that are sometimes connected to Formik and sometimes not, I would export two different components:
The base Checkbox component that has nothing to do with Formik. It should just use a normal input
A Field wrapper around that Checkbox component
While the Field component can take a type, causing it to render the corresponding input, it can also take a render prop to render whatever you want, and it is passed all of the state Formik manages for that field.
For example, your Checkbox and CheckboxField components could looks something like this:
const Checkbox = (props) => {
...
return (
<div className={myClass1}>
<input type='checkbox' checked={props.checked} onChange={props.onChange} />
<label ...>{props.label}</label>
</div>
)
};
const CheckboxField = (props) => {
return (
<Field name={props.name}>
{(field) => <Checkbox label={props.label} {...field} />}
</Field>
)
}
Now you use have two components that render exactly the same, but one is meant to be used within a Formik form (CheckboxField) and the other can be used anywhere (Checkbox).
Consider the following component tree
<Header />
<SearchBar />
<ProductList />
<Product />
In the SearchBar component I want to catch the value of an input and send that value to ProductList to dynamically render Product components based on the value received.
Is there a way to communicate between SearchBar and ProductList without the need of a component that wraps both of them or without Redux ?
According to React's page "React is all about one-way data flow down the component hierarchy" which means that data passing horizontally should be avoided.
In your case you could have a parent component that render <SearchBar/> and <ProductList/>based on state. For example, whenever the user enter with a value in <SearchBar> it changes the state on the parent component, and consequently <ProductList> will be rendered again.
As Osman said, you could pass the value of the SearchBar into a state and then from the state into the Product using a function.
handleChange(event) {
this.setState({
newProduct: event.currentTarget.value
)}
}
render() {
return(
<SearchBar onChange={this.handleChange} />
<Product content={this.state.newProduct} />
);
}
Make sure you don't forget to bind the function in the constructor.
<TextField
onChange={props.onChangeTextField}
ref="questionInput"
style={styles.textField}
value={props.existingValue}
fullWidth={true}
/>
I was trying to give an input field in a stateless function component to be able to focus it when the component loads like this:
componentWillMount = () => {
this.refs.questionInput.focus();
console.log('test')
}
}
But I got the error:
Stateless function components cannot have refs.
So is there a way to focus an input field in React without a ref?
You should wrap your input component with forwardRef function. Something like this:
import * as React from "react";
const TextInput = React.forwardRef(
(props, ref) => <input ref={ref} {...props} />
);
export default TextInput;
Note that it will add a second argument to your functional component, which you should pass to the DOM element as ref prop.
Yes. However your method of using ref is really outdated. You should update to the latest version of React (currently 16.3.2) and follow the official documentation
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
let textInput = React.createRef();
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
No, you need to change the functional component into a class.
You may not use the ref attribute on functional components because they don’t have instances
You should also use the newer callback API to set the ref:
ref={ref => { this.questionInput = ref }}
Or createRef for v16.3.
Adding the autoFocus prop to the input component might do the trick if you just want it to be focused on mount:
<TextField autoFocus ..restOfProps />