简体   繁体   中英

State not updating in different component

I have a searchbar component that I used context to import into another component. The state of the searchbar in its own component works but when I use the context to import it to another component it does not work. I have used other contexts in my project and they have worked but the searchbar state doesn't. I have no idea where to start, or how to go about fixing it. Can someone point me in the right direction?

export const SearchInput = () => {
const [searchInput, setSearchInput] = useState('');

    const handleSubmit = (e) => {
        e.preventDefault()
    }

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type='text'
                    className='search-input'
                    name='search-movies'
                    value={searchInput}
                    onChange={(e) => setSearchInput(e.target.value)} />
            </form>
        </div>
    )
}

//Use Context Component

export const SearchContext = React.createContext()

export function SearchProvider({ children }) {
    const [searchInput, setSearchInput] = useState('');
    

    const value = {
        searchInput
    }

    return (
        <div>
            <SearchContext.Provider value={value}>
                {children}
            </SearchContext.Provider>
        </div>
    )
}

const Movies = () => {

    const { data, loading, isErr } = useFetch([
        `https://api.themoviedb.org/3/list/7077601?api_key=${process.env.REACT_APP_API_KEY}&language=en-US`,
        `https://api.themoviedb.org/3/list/7078334?api_key=${process.env.REACT_APP_API_KEY}&language=en-US`,
        `https://api.themoviedb.org/3/list/7078244?api_key=${process.env.REACT_APP_API_KEY}&language=en-US`
    ]);

    const { watchList, handleClick } = useContext(WatchListContext);
    const { searchInput } = useContext(SearchContext)

    const [moviePoster, setmoviePoster] = useState(`giphy (1).gif`);
    const [movieTitle, setmovieTitle] = useState('');
    const [movieDescription, setmovieDescription] = useState('')

    const styles = {
        backgroundImage: `url(${moviePoster})`
    };


    SwiperCore.use([Navigation, Pagination, Scrollbar, A11y]);

    return (

        <div className='movie-container'>
            {isErr && <div className="error">{isErr}</div>}
            {loading && <Spinner animation="border" variant="secondary" className="spinner" >
                <span>Loading...</span>
            </Spinner>}
            <div className='movie-hero' style={styles}></div>
            <div className="contains-descriptions">
                <h2 className="hero-movie-title show-movie">{movieTitle}</h2>
                <p className="hero-movie-description show-movie">{movieDescription}</p>
            </div>

            <section className="movies">
                <h2 style={{ color: 'white', marginLeft: '20px' }}>Action </h2>
                {data && <Swiper
                    spaceBetween={10}
                    slidesPerView={6}
                    pagination={{ clickable: true }}
                    scrollbar={{ draggable: true }}
                    onSlideChange={() => console.log('slide change')}
                    onSwiper={(swiper) => console.log(swiper)}
                >
                    {data && data[0].items.map(movie =>
                        <SwiperSlide key={movie.id}>
                            <div className='movie' >
                                <img onMouseOver={() => {
                                    setmoviePoster(`${"https://image.tmdb.org/t/p/original" + movie.poster_path}`);
                                    setmovieTitle(movie.original_title);
                                    setmovieDescription(movie.overview);
                                }}
                                    src={'https://image.tmdb.org/t/p/original' + movie.poster_path} width='250' height='300'
                                    alt='Promotional Poster For Movie'
                                />
                                <button className="watchlist-btn"
                                    onClick={() => handleClick(movie.original_title)}>
                                    {watchList.includes(movie.original_title) ?
                                        <i className="fas fa-minus-circle"></i> :
                                        <i className="fas fa-plus-circle"></i>}
                                </button>
                            </div>
                        </SwiperSlide>
                    )
                    }
                </Swiper>}
            </section>

I'm assuming a component tree that looks something like this:

+-- SearchProvider
|   +-- SearchInput
|   +-- Movies

Your SearchProvider should be providing both the state and the state setter as its value:

export const SearchContext = React.createContext()

export function SearchProvider({ children }) {
    const [searchInput, setSearchInput] = useState('');
    
    const value = {
        searchInput,
        setSearchInput
    };

    return ...
}

Your SearchInput should no longer be controlling its own local state. That state now has to be shared with the rest of the tree. Instead, it subscribes to the context and updates it directly:

export const SearchInput = () => {
    const { searchInput, setSearchInput } = React.useContext(SearchContext);

    const handleSubmit = (e) => {
        e.preventDefault()
    };

    return ...
}

Why are you using context and not just useState and props?

I think it would work with something like the following:

export const SearchInput = (props) => {

    const handleSubmit = (e) => {
        e.preventDefault()
    }

    return (
        <div>
            <form onSubmit={handleSubmit}>
                <input type='text'
                    className='search-input'
                    name='search-movies'
                    value={props.value}
                    onChange={(e) => props.onChange(e.target.value)} />
            </form>
            {props.children}
        </div>
    )
}


export function SearchCompoent({ children }) {
    const [searchInputValue, setSearchInputValue] = useState('');
    return (
        <SearchInput value={searchInputValue}>
            {children}
        </SearchInput>
    )
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM