moroshko / react-autosuggest

WAI-ARIA compliant React autosuggest component
http://react-autosuggest.js.org
MIT License
5.97k stars 586 forks source link

Autosuggest with Algolia and Material UI #783

Closed Sarath81198 closed 3 years ago

Sarath81198 commented 3 years ago

I'm using Material UI and Algolia on my React app. I'm trying to implement my customised autocomplete with my customised Search box.

Here's my Search box component

import React, { useState, useEffect } from 'react';
import InputBase from '@material-ui/core/InputBase';
import { fade, makeStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton'
import Lottie from 'react-lottie';
import searchIcon from './../../assets/animations/SearchIcon.json'
import { useHistory } from "react-router-dom"
import queryString from 'query-string'
import { connectSearchBox } from 'react-instantsearch-dom';

const useStyles = makeStyles((theme) => ({
    search: {
        position: 'relative',
        borderRadius: theme.shape.borderRadius,
        backgroundColor: fade(theme.palette.common.black, 0.15),
        '&:hover': {
            backgroundColor: fade(theme.palette.common.black, 0.25),
        },
        marginLeft: 0,
        marginRight: 20,
        width: '100%',
        [theme.breakpoints.up('sm')]: {
            marginLeft: theme.spacing(1),
            width: 'auto',
        },
    },
    inputRoot: {
        color: 'inherit',
    },
    inputInput: {
        padding: theme.spacing(1, 1, 1, 1),
        // vertical padding + font size from searchIcon
        paddingLeft: `calc(1em + ${theme.spacing(1)}px)`,
        transition: theme.transitions.create('width'),
        width: '100%',
        [theme.breakpoints.up('xs')]: {
            width: '18ch',
            '&:focus': {
                width: '30ch',
            },
        },
    },
}));

function AlgoliaSearchBox({ refine }, {...inputProps}) {
    const classes = useStyles();
    const history = useHistory()
    const [searchIconAnimationIsStopped, setSearchIconAnimationIsStopped] = useState(true)
    const currentPath = window.location.pathname
    const { q } = queryString.parse(window.location.search)
    const [query, setQuery] = useState(q)

    useEffect(() => {
        refine(q)    
    }, [q, refine])

    const searchIconOptions = {
        loop: true,
        autoplay: false,
        animationData: searchIcon,
        rendererSettings: {
            preserveAspectRatio: 'xMidYMid slice'
        }
    };

    const handleQueryOnSubmit = (event) => {
        event.preventDefault()
        const searchQuery = event.target.q.value
        refine(searchQuery)
        history.push(`/items?q=${searchQuery}`)
    }

    if(currentPath !== '/items'){
        return null
    }
    else{
        return (
            <div className={classes.search}>
                <form action="" role="search" 
                    onSubmit={(e) => {
                        e.preventDefault()
                        handleQueryOnSubmit(e)
                        }}>
                    <InputBase
                        name="q"
                        id="q"
                        {...inputProps}

                        classes={{
                            root: classes.inputRoot,
                            input: classes.inputInput,
                        }}
                        inputProps={{ 'aria-label': 'search' }}
                        endAdornment = {
                                <IconButton
                                    color="primary"
                                    type="submit"
                                    onClick={() => {
                                        setSearchIconAnimationIsStopped(false)
                                        setTimeout(() => {
                                            setSearchIconAnimationIsStopped(true)
                                        }, 200);
                                    }}>
                                    <Lottie
                                        options={searchIconOptions}
                                        isStopped={searchIconAnimationIsStopped}
                                        height={20}
                                        width={20}
                                        speed={3}
                                    />
                                </IconButton>
                        }
                    />
                </form>
            </div>
        );
    }
}

const SearchBox = connectSearchBox(AlgoliaSearchBox)

export default SearchBox

And here's my Auto complete component:

import React, { useState} from 'react'
import AutoSuggest from 'react-autosuggest';
import { Highlight, connectAutoComplete } from 'react-instantsearch-dom';
import SearchBox from './SearchBox'

function AutoComplete(props) {
    const { currentRefinement, hits, refine } = props
    const [value, setValue] = useState(currentRefinement)

    const onChange = (event, {newValue}) => {
        setValue(newValue)
    }

    const onSuggestionsFetchRequested = ({ value }) => {
        refine(value)
    }

    const onSuggestionsClearRequested = () => {
        refine()
    }

    const getSuggestionValue = (hit) => {
        return hit.item_name
    }

    const renderSuggestion = (hit) => {
        return <Highlight attribute="item_name" hit={hit} tagName="mark" />
    }

    const inputProps = {
        placeholder: 'Search for a product...',
        onChange: onChange,
        value,
    };

    const renderInputComponent = inputProps => (
            <SearchBox {...inputProps} />
    );

    return (
        <AutoSuggest
            suggestions={hits}
            onSuggestionsFetchRequested={onSuggestionsFetchRequested}
            onSuggestionsClearRequested={onSuggestionsClearRequested}
            getSuggestionValue={getSuggestionValue}
            renderSuggestion={renderSuggestion}
            inputProps={inputProps}
            renderInputComponent={renderInputComponent}
        />
    )
}

export default connectAutoComplete(AutoComplete)

The error I get on console is

index.js:1 Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Check the render method of `Autowhatever`.
    in ConnectorWrapper (at AutoComplete.js:37)
    in div (created by Autowhatever)
    in Autowhatever (created by Autosuggest)
    in Autosuggest (at AutoComplete.js:41)
    in AutoComplete (created by AlgoliaAutoComplete(AutoComplete))
    in AlgoliaAutoComplete(AutoComplete) (created by Context.Consumer)
    in ConnectorWrapper (at GuestNavbar.js:59)
    in div (at GuestNavbar.js:57)
    in div (created by ForwardRef(Toolbar))
    in ForwardRef(Toolbar) (created by WithStyles(ForwardRef(Toolbar)))
    in WithStyles(ForwardRef(Toolbar)) (at GuestNavbar.js:49)
    in header (created by ForwardRef(Paper))
    in ForwardRef(Paper) (created by WithStyles(ForwardRef(Paper)))
    in WithStyles(ForwardRef(Paper)) (created by ForwardRef(AppBar))
    in ForwardRef(AppBar) (created by WithStyles(ForwardRef(AppBar)))
    in WithStyles(ForwardRef(AppBar)) (at GuestNavbar.js:48)
    in ElevationScroll (at GuestNavbar.js:47)
    in HiddenJs (created by WithWidth(HiddenJs))
    in WithWidth(HiddenJs) (created by Hidden)
    in Hidden (at GuestNavbar.js:46)
    in div (at GuestNavbar.js:44)
    in GuestNavbar (at Navbar.js:10)
    in div (at Navbar.js:9)
    in Navbar (at App.js:119)
    in InstantSearch (at App.js:117)
    in div (at App.js:116)
    in ThemeProvider (at App.js:114)
    in LastLocationProvider (created by Context.Consumer)
    in withRouter(LastLocationProvider) (at App.js:113)
    in MuiPickersUtilsProvider (at App.js:112)
    in Router (created by BrowserRouter)
    in BrowserRouter (at App.js:111)
    in App (at src/index.js:18)
    in StrictMode (at src/index.js:17)
    in Provider (at src/index.js:16)

when I use the one in the example code in the doc

    const renderInputComponent = inputProps => (
        <div>
               <input {...inputProps} />
        </div>
    );

it works fine.

What wrong am I doing? Can someone give me a solution how use renderInputComponent with a customised input component?

TIA

SalTor commented 3 years ago

@Sarath81198 did you solve this issue?

bertyhell commented 2 years ago

I have the same issue. @Sarath81198 , did you find a fix?

nfort commented 2 years ago

@bertyhell i fix it in #839