在将状态传递给useState挂钩后,它是未定义的,为什么?

时间:2020-06-21 05:55:38

标签: javascript reactjs react-hooks

我正在使用google youtube api播放一些视频。不幸的是,当用户单击视频时,我无法传递视频详细信息。 (我知道该警告,将会通过在缩略图中添加索引来尽快解决此问题。)

问题是(它也在帖子的中间,但恐怕会丢失):为什么将我的searchedValue.videos更改为undefined?

我有一个工作版本: 单击视频缩略图时,可以得到预期的结果。 picture of my working version

这是它的代码:

App.js

import React, { useState, createContext } from "react";
import NavBar from "./NavBar";
import youtube from "../apis/youtube";
import VideoList from "./VideoList";
import VideoDetail from "./VideoDetail";

export const VideoContext = createContext();

function App() {
    const [ searchedValue, setSearchedValue ] = useState({ videos: [], selectedVideo: null });

    const API_KEY = process.env.REACT_APP_API_KEY;

    const handleSearch = async (inputText) => {
        const response = await youtube.get("/search", {
            params: {
                q: inputText,
                part: "snippet",
                type: "video",
                maxResults: 5,
                key: API_KEY
            }
        });
        setSearchedValue({ videos: response.data.items });
    };

    const handleSelectedVideo = (singleRenderedVideo) => {
        console.log("from App.js: ", singleRenderedVideo);
        // setSearchedValue({ selectedVideo: singleRenderedVideo });
    };

    return (
        <div className="ui container">
            <NavBar handleSearch={handleSearch} />
            <VideoContext.Provider value={handleSelectedVideo}>
                <p>I got {searchedValue.videos.length} results.</p>
                {/* <VideoDetail video={searchedValue.selectedVideo} /> */}
                <VideoList handleSelectedVideo={handleSelectedVideo} listOfVideos={searchedValue.videos} />
            </VideoContext.Provider>
        </div>
    );
}

export default App;

NavBar.js

import React, { useState } from "react";

const NavBar = (props) => {
    const [ inputText, setInputText ] = useState("");

    const handleSearch = (event) => {
        props.handleSearch(inputText);
        event.preventDefault();
    };

    const handleChange = (event) => {
        setInputText(event.target.value);
    };

    return (
        <div className="search-bar ui segment">
            <form onSubmit={handleSearch} className="ui form">
                <div className="field">
                    <label>Video Search</label>
                    <input
                        type="text"
                        placeholder="Type in to search for videos"
                        onChange={handleChange}
                        value={inputText}
                    />
                </div>
            </form>
        </div>
    );
};

export default NavBar;

VideoDetail.js

import React from "react";

const VideoDetail = ({ video }) => {
    if (!video) {
        return <div>Loading...</div>;
    }

    return <div>{video.snippet.title}</div>;
};

export default VideoDetail;

VideoItem.js

import "./VideoItem.css";
import React, { useContext } from "react";
import { VideoContext } from "./App";

const VideoItem = ({ singleRenderedVideo }) => {
    const videoContext = useContext(VideoContext);
    return (
        <div onClick={() => videoContext(singleRenderedVideo)} className="video-item item">
            <img className="ui image" src={singleRenderedVideo.snippet.thumbnails.medium.url} alt="img" />
            <div className="content">
                <div className="header">{singleRenderedVideo.snippet.title}</div>
            </div>
        </div>
    );
};

export default VideoItem;

VideoList.js

import React from "react";
import VideoItem from "./VideoItem";

const VideoList = ({ listOfVideos }) => {
    const renderedListOfVideos = listOfVideos.map((video) => {
        return <VideoItem singleRenderedVideo={video} />;
    });
    return <div className="ui relaxed divided list">{renderedListOfVideos}</div>;
};

export default VideoList;

但是在App.js中,当我尝试设置selectedVideo的状态时:

const handleSelectedVideo = (singleRenderedVideo) => {
        // console.log("from App.js: ", singleRenderedVideo);
        setSearchedValue({ selectedVideo: singleRenderedVideo });
    };

我收到以下错误:

not working version

更改代码的整个App.js。

import React, { useState, createContext } from "react";
import NavBar from "./NavBar";
import youtube from "../apis/youtube";
import VideoList from "./VideoList";
import VideoDetail from "./VideoDetail";

export const VideoContext = createContext();

function App() {
    const [ searchedValue, setSearchedValue ] = useState({ videos: [], selectedVideo: null });

    const API_KEY = process.env.REACT_APP_API_KEY;

    const handleSearch = async (inputText) => {
        const response = await youtube.get("/search", {
            params: {
                q: inputText,
                part: "snippet",
                type: "video",
                maxResults: 5,
                key: API_KEY
            }
        });
        setSearchedValue({ videos: response.data.items });
    };

    const handleSelectedVideo = (singleRenderedVideo) => {
        // console.log("from App.js: ", singleRenderedVideo);
        setSearchedValue({ selectedVideo: singleRenderedVideo });
    };

    return (
        <div className="ui container">
            <NavBar handleSearch={handleSearch} />
            <VideoContext.Provider value={handleSelectedVideo}>
                <p>I got {searchedValue.videos.length} results.</p>
                <VideoDetail video={searchedValue.selectedVideo} />
                <VideoList handleSelectedVideo={handleSelectedVideo} listOfVideos={searchedValue.videos} />
            </VideoContext.Provider>
        </div>
    );
}

export default App;

2 个答案:

答案 0 :(得分:1)

在类组件中,如果设置状态并仅提供部分对象,则react将与完整状态进行浅表合并。在功能组件中不会发生这种情况。无论您将状态设置为什么,那就是状态。所以这段代码:

setSearchedValue({ selectedVideo: singleRenderedVideo })

...仅将状态设置为具有selectedVideo属性的对象。它不再具有视频属性。

您有两个选择:

  1. 自己做个浅薄的合并
setSearchedValue(previous => ({
  ...previous,
  selectedVideo: singleRenderedVideo
}));
  1. 具有两个单独的状态变量。对于像您这样的情况,我建议您这样做。
const [ videos, setVideos ] = useState([]);
const [ selectedVideo, setSelectedVideo ] = useState(null);

// ...

setSelectedVideo(singleRenderedVideo);

答案 1 :(得分:0)

searchedValue设置为{selectedVideo:...}。另一个属性,因为新值不具有该属性。设置searchedValue时,应包括您的视频属性。应该设置为setSearchedValue({... searchedValue,selectedVideo:newValue})