Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autosuggest with Algolia and Material UI #783

Closed
Sarath81198 opened this issue Jan 2, 2021 · 3 comments
Closed

Autosuggest with Algolia and Material UI #783

Sarath81198 opened this issue Jan 2, 2021 · 3 comments

Comments

@Sarath81198
Copy link

Sarath81198 commented Jan 2, 2021

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
Copy link

SalTor commented Aug 12, 2021

@Sarath81198 did you solve this issue?

@bertyhell
Copy link

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

@nfort
Copy link

nfort commented Feb 9, 2022

@bertyhell
i fix it in #839

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants