react-autosuggest with useRef - reactjs

I am trying to create an input with the autosuggest. As I am using tailwind, there is no this kind of input there and therefore I came across react-autosuggest. The thing is however, I need to use a ref for this Autosuggest Input, cause I need to submit after a select and logically get the value of this Autosuggest Input on button click/submit. Here is part of my code (not everything). The code was working with normal input, so ne help needed apart from fixing the Ref problem:
import { useState, useEffect, useRef } from 'react';
import Autosuggest from 'react-autosuggest';
export const SearchBar = () => {
const autosuggestInput = useRef(null);
....
const city = autosuggestInput.current.value;
......
return(
<Autosuggest
type="text"
ref={autosuggestInput}
className="py-3 px-4 block w-full shadow-sm focus:ring-blue-500 focus:border-blue-500 border-gray-300 rounded-md"
/>
)
}
Here I am getting the Error: Cannot read property 'value' of undefined. Which suggests that the ref is not working. I am using next.js and therefore also functional components. Maybe that is the problem?

By default your ref line won't do anything. Because ref only applies to the Host component, such as div, p, button etc.
<div ref={ref}>ABC</div>
The above line will work. Ok, so in order to get the ref onto a custom component, there's some ways. One is to use a forwardRef, however either way the interface of react-autosuggest needs to allow you do that. I just read a bit, doesn't seem so.
However if you just want the value, seems the documentation is asking you do this
const inputProps = {
placeholder: 'Type a programming language',
value,
onChange: this.onChange
};
return (
<Autosuggest
...
inputProps={inputProps}
/>
);
Try their demo first. Basically any input is driven by value and onChange. The rest of them are all sugar code.

React auto-suggest is a controlled component and so needs some mandatory parameters passed into it such as the value, suggestions, onChange handler etc. which is what is giving you the error and NOT useRef.
See Basic Usage here : https://www.npmjs.com/package/react-autosuggest
The following props need to be passed through to the AutoSuggest component (From the Basic Usage npm docs) :
// Finally, render it!
return (
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
inputProps={inputProps}
/>
);

Related

React Hook Form's register function does not work when using custom components

I'm refactoring some code in my app and I noticed that when I moved my input element to be its own reusable component, hook-form's register function stopped working. This can be fixed if you use the plain input element, but I would like to use my own component. Here's a stack blitz with a reproducible example: https://stackblitz.com/edit/react-ts-9bafks?file=App.tsx
If you check what register('text') actually gives you console.log(register("text")) you will see that there is a ref. You have to make your custom inputs to forward that ref.
const TextInput: FC<Props> = React.forwardRef(({ error, ...props }, ref) => {
return (
<div>
<p> {error} </p>
<input {...props} ref={ref}/>
</div>
);
});

Can not get in order TS with forwardRef in React App

I have component which so far was used as functional one like this (thunk is "any" temporarily for simplicity)
interface Props {
thunkFetchMovies: any;
}
const SearchInput = (props:Props) => {
const { thunkFetchMovies } = props;
return (
<div className="TopBar__center">
<div className="search">
</div>
</div>)
}
Due to need of modifying DIV with className 'search' I try to rewrite the component with forwardRef. Have already checked few suggestions from websites, but nothing works as expected.
Tried to follow these sources:
https://fettblog.eu/typescript-react-generic-forward-refs/
https://www.carlrippon.com/react-forwardref-typescript/
as well as few similar questions here, but it does not work as expected. How should I type it?
If you need to modify the css you don't need the ref of the element in the Dom.
You can edit the class name based on props, for example:
<button className={props.foo == "bar" ? "search":""} />

React Hooks - Input loses focus when 1 character is typed in

I'm playing with React Hooks - rewriting a form to use hook concepts. Everything works as expected except that once I type any 1 character into the input, the input loses focus.
I guess there is a problem that the outside of the component doesn't know about the internal changes in the component, but how do I resolve this issue?
Here is the useForm Hook:
import React, { useState } from "react";
export default function useForm(defaultState, label) {
const [state, setState] = useState(defaultState);
const FormComponent = () => (
<form>
<label htmlFor={label}>
{label}
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
/>
</label>
</form>
);
return [state, FormComponent, setState];
}
Here is the component that uses the Hook:
function App() {
const [formValue, Form, setFormValue] = useForm("San Francisco, CA", "Location");
return (
<Fragment>
<h1>{formValue}</h1>
<Form />
</Fragment>
);
}
While answer by Kais will solve the symptoms, it will leave the cause unaddressed. It will also fail if there are multiple inputs - which one should autofocus itself on rerender then?
The issue happens when you define a component (FormComponent) inside the scope of another function which is called each render of your App component. This gives you a completely new FormComponent each time your App component is rerendered and calls useState. That new component is then, well, without focus.
Personally I would feel agains returning components from a hook. I would instead define a FormComponent component, and only return state from useForm state.
But, a working example closest to your original code could be:
// useForm.js
import React, { useState } from "react";
// Define the FormComponent outside of your useForm hook
const FormComponent = ({ setState, state, label }) => (
<form>
<label htmlFor={label}>
{label}
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
/>
</label>
</form>
);
export default function useForm(defaultState, label) {
const [state, setState] = useState(defaultState);
return [
state,
<FormComponent state={state} setState={setState} label={label} />,
setState
];
}
// App.js
import useForm from "./useForm";
export default function App() {
const [formValue, Form] = useForm("San Francisco, CA", "Location");
return (
<>
<h1>{formValue}</h1>
{Form}
</>
);
}
Here's a sandbox
When you enter any text in input box. Parent Component is also re-rendering. So you need to make focus on input manually.
For this, use autoFocus in input tag
<input
type="text"
id={label}
value={state}
placeholder={label}
onChange={e => setState(e.target.value)}
autoFocus
/>
The above answers didn't work for me. The solution that worked for me was much simpler and, for that reason, less obvious.
The Problem
Essentially, the value that I was changing with the input was also being used for each key in a list of inputs.
Hence, when I updated the value the key would change and React would detect that it's different relative to the last key and create a new input in its place. As a new input it wouldn't focus on itself.
However, by using autoFocus it would automatically focus on the newly created input. But the issue wasn't fixed as it was obvious that the input was continually going through a cycle of un-focus and focus.
Here's an article demonstrating the problem.
The Fix
Update the key to an unchangeable value so React would have a stable reference to the list items. In my case I just updated it to the index. This is not ideal (React docs recommend using a stable ID), but in my situation it was okay because the order of the items won't change.
The first solution actually worked for me , initially the functional component which contained the text field was part of the main functional component , i was facing the same issue but when i extracted the text-field component into another page and imported it it worked fine
This was my component
<Paper >
<div>
<div style={{padding:'10px' ,display:'flex'}} >
<inputstyle={{marginRight:'5px'}} value={val} onChange={(e)=>{setVal(e.target.value)}} />
</div>
</div>
</Paper>

Autofocus on reactstrap alerts using react functional component

I am using react hooks for my frontend designs and while creating a register form I have used various validations and I am depicting errors using reactstrap warning alerts.
And things are working fine but when focus is not implemented on these alers means when my page shows any of alert, it doesn't focus on that automatically.
I have tried basic codes for autofocus/ autoFocus or Focus() but nothing is working as per need.
My alert code look as shown below:
{
showAlreadyRegisteredAlert?
<Alert variant="warning" onClose={() => setShowAlreadyRegisteredAlert(false)} dismissible>
<p className="mb-0">
{content}
</p>
</Alert>
:null
}
I am just writing these alert codes in between my form inputs and whenever I need to call any of them I simply setValue for the commponent and alert box is called but still it lacks autofocus.
Any help will be appreciated. Thanks in advance!
I found the desired solution as I wanted my page should automatically focused on appearing alert boxes. I searched react-hooks official documention and get to know that we can use "useRef" for the purpose and below is my code for better understanding and clarification:
First: import useRef from react.
import React, {useState, useRef} from "react";
Second: create const with desired name using useRef as null.
const inputUser = useRef(null);
Third: set focus on your ref const after alert.
setShowAlreadyRegisteredAlert(true);
inputUser.current.focus();
Fourth: pass ref as const which you defined in step 2 inside your input field.
ref= {inputUser}

react-final-form with multiple select

I'm trying to build a form with a multiple value Select component by Material-UI using react-final-form. Somehow with single Select, I can get the value but with multiple, it doesn't. Somehow it seems like react-final-form is holding its own value internally.
Here's a the guiding link from Material-UI for building multiple Select:
https://codesandbox.io/s/sr6pf
I tried to replicate the very first example (without using react hook) in my form and I still miss something ?
https://codesandbox.io/embed/react-final-form-material-ui-example-jfmoe
What should I add to my Component to make this work ?
Thanks,
For some reasons I've managed to figure out the solution for my own question. The proper answer is to create a custom MultiSelect component instead of reusing the one from final-form-material-ui.
Notes: I've tried to use <Select /> from final-form-material-ui but adding multiple prop to the component will not be passed to , this is weird.
So, my custom component would look like this, almost similar to the one from their github with multiple prop added.
import React from 'react';
import FormControl from '#material-ui/core/FormControl';
import FormHelperText from '#material-ui/core/FormHelperText';
import InputLabel from '#material-ui/core/InputLabel';
import Select from '#material-ui/core/Select';
function SelectMulti({
input: { name, value, onChange, ...restInput },
meta,
label,
formControlProps,
...rest
}) {
const showError =
((meta.submitError && !meta.dirtySinceLastSubmit) || meta.error) &&
meta.touched;
return (
<FormControl {...formControlProps} error={showError}>
<InputLabel htmlFor={name} shrink>
{label}
</InputLabel>
<Select
{...rest}
multiple
name={name}
value={value}
onChange={onChange}
inputProps={restInput}
/>
{showError && (
<FormHelperText>{meta.error || meta.submitError}</FormHelperText>
)}
</FormControl>
);
}
SelectMulti.propTypes = {};
export default SelectMulti;
Hope this help someone in the future
I was able to solve this with by setting the fomat as such
<Field
name="concepts"
component={Select}
displayEmpty={trie}
multiple={true}
value={[]}
format={value => value || []}
/>
As per https://github.com/erikras/redux-form-material-ui/issues/212#issuecomment-358376925

Resources