How to call a function method in a component class render method? getting Uncaught TypeError: Cannot read property 'value' of null in React
How to call a function method in a component class render method? getting Uncaught TypeError: Cannot read property 'value' of null in React
我正在创建一个同时使用组件和功能组件的 Web 应用程序。我使用组件 class 创建了 Regsiter
和 Login
,但我正在努力使用组件 class 创建 Searchbar
,所以我使用函数组件创建了它。我对我应该在哪里调用搜索功能感到困惑?当函数本身只是一个函数组件时,它本身没有问题 运行,而且我没有 Register
或 Login
的任何代码,所以我不相信错误与函数本身有关。但是,当我为 Register
和 Login
添加代码并从 render 调用该函数时,它似乎不起作用并且 returns 为 null,我是否遗漏了什么?有没有可能我应该用 componentDidMount()
做点什么?
import React, { Component, useState } from "react";
import axios from 'axios';
import { Switch, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import styled from "styled-components";
import AuthService from "./services/auth.service";
import Login from "./components/login.component";
import Register from "./components/register.component";
import Home from "./components/home.component";
import Profile from "./components/profile.component";
import BoardUser from "./components/board-user.component";
import BoardCreator from "./components/board-creator.component";
import BoardAdmin from "./components/board-admin.component";
import MovieList from "./components/movie-list.component";
// import AuthVerify from "./common/auth-verify";
import EventBus from "./common/EventBus";
const Container = styled.div`
display: flex;
flex-direction: column;
`;
const AppName = styled.div`
display: flex;
flex-direction: row;
align-items: center;
`;
const Header = styled.div`
background-color: black;
color: white;
display: flex;
justify-content: space-between;
flex-direction: row;
align-items: center;
padding: 10px;
font-size: 25px;
font-weight: bold;
box-shadow: 0 3px 6px 0 #555;
`;
const SearchBox = styled.div`
display: flex;
flex-direction: row;
padding: 10px 10px;
border-radius: 6px;
margin-left: 20px;
width: 50%;
background-color: white;
`;
const SearchInput = styled.input`
color: black;
font-size: 16px;
font-weight: bold;
border: none;
outline: none;
margin-left: 15px;
`;
const MovieListContainer = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 30px;
gap: 25px;
justify-content: space-evenly;;
`;
class App extends Component {
constructor(props) {
super(props);
this.logOut = this.logOut.bind(this);
this.state = {
showCreatorBoard: false,
showAdminBoard: false,
currentUser: undefined,
timeoutId: "",
updateTimeoutId: ""
};
}
componentDidMount() {
const user = AuthService.getCurrentUser();
if (user) {
this.setState({
currentUser: user,
showCreatorBoard: user.roles.includes("ROLE_MODERATOR"),
showAdminBoard: user.roles.includes("ROLE_ADMIN"),
});
}
EventBus.on("logout", () => {
this.logOut();
});
}
componentWillUnmount() {
EventBus.remove("logout");
}
logOut() {
AuthService.logout();
this.setState({
showCreatorBoard: false,
showAdminBoard: false,
currentUser: undefined,
});
}
render() {
const { currentUser, showCreatorBoard, showAdminBoard} = this.state;
return (
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark">
<Link to={"/"} className="navbar-brand">
Movie App
</Link>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/home"} className="nav-link">
Home
</Link>
</li>
{showCreatorBoard && (
<li className="nav-item">
<Link to={"/mod"} className="nav-link">
Moderator Board
</Link>
</li>
)}
{showAdminBoard && (
<li className="nav-item">
<Link to={"/admin"} className="nav-link">
Admin Board
</Link>
</li>
)}
{currentUser && (
<li className="nav-item">
<Link to={"/user"} className="nav-link">
User
</Link>
</li>
)}
</div>
<Search />
{currentUser ? (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/profile"} className="nav-link">
{currentUser.username}
</Link>
</li>
<li className="nav-item">
<a href="/login" className="nav-link" onClick={this.logOut}>
LogOut
</a>
</li>
</div>
) : (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/login"} className="nav-link">
Login
</Link>
</li>
<li className="nav-item">
<Link to={"/register"} className="nav-link">
Sign Up
</Link>
</li>
</div>
)}
</nav>
<div className="container mt-3">
<Switch>
<Route exact path={["/", "/home"]} component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
<Route exact path="/profile" component={Profile} />
<Route path="/films"
component={MovieList}
/>
<Route path="/user" component={BoardUser} />
<Route path="/creator" component={BoardCreator} />
<Route path="/admin" component={BoardAdmin} />
</Switch>
</div>
<MovieListContainer>
<MovieList></MovieList>
<MovieList></MovieList>
<MovieList></MovieList>
<MovieList></MovieList>
</MovieListContainer>
{ /*<AuthVerify logOut={this.logOut}/> */ }
</div>
);
}
}
搜索
function Search() {
const [searchQuery, setSearchQuery] = useState("");
const [timeoutId, updateTimeoutId] = useState();
const fetchData = async (searchString) => {
const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
console.log(response);
};
const onTextChange = (e) => {
clearTimeout(timeoutId);
setSearchQuery(e.target.value);
const timeout = setTimeout(() => fetchData(e.target.value), 500);
updateTimeoutId(timeout);
};
return(
<div>
<SearchBox>
<SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
</SearchBox></div>
);
}
export default App;
假设您使用的是 React 16 或更早版本,问题出在这一行:
const timeout = setTimeout(() => fetchData(e.target.value), 500);
直到最近,React 还试图重用事件对象,因此一旦同步代码完成 运行,它就会将 e.target 设置为 null。结果,到超时结束时,e.target
为空,因此 e.target.value
抛出异常。
选项 1:将值保存在局部变量中并使用它
const onTextChange = (e) => {
clearTimeout(timeoutId);
const value = e.target.value;
setSearchQuery(value);
const timeout = setTimeout(() => fetchData(value), 500);
updateTimeoutId(timeout);
};
选项 2:告诉 React 不要重用这个事件对象
const onTextChange = (e) => {
e.persist();
clearTimeout(timeoutId);
setSearchQuery(e.target.value);
const timeout = setTimeout(() => fetchData(e.target.value), 500);
updateTimeoutId(timeout);
};
更多信息,see this page
我正在创建一个同时使用组件和功能组件的 Web 应用程序。我使用组件 class 创建了 Regsiter
和 Login
,但我正在努力使用组件 class 创建 Searchbar
,所以我使用函数组件创建了它。我对我应该在哪里调用搜索功能感到困惑?当函数本身只是一个函数组件时,它本身没有问题 运行,而且我没有 Register
或 Login
的任何代码,所以我不相信错误与函数本身有关。但是,当我为 Register
和 Login
添加代码并从 render 调用该函数时,它似乎不起作用并且 returns 为 null,我是否遗漏了什么?有没有可能我应该用 componentDidMount()
做点什么?
import React, { Component, useState } from "react";
import axios from 'axios';
import { Switch, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import styled from "styled-components";
import AuthService from "./services/auth.service";
import Login from "./components/login.component";
import Register from "./components/register.component";
import Home from "./components/home.component";
import Profile from "./components/profile.component";
import BoardUser from "./components/board-user.component";
import BoardCreator from "./components/board-creator.component";
import BoardAdmin from "./components/board-admin.component";
import MovieList from "./components/movie-list.component";
// import AuthVerify from "./common/auth-verify";
import EventBus from "./common/EventBus";
const Container = styled.div`
display: flex;
flex-direction: column;
`;
const AppName = styled.div`
display: flex;
flex-direction: row;
align-items: center;
`;
const Header = styled.div`
background-color: black;
color: white;
display: flex;
justify-content: space-between;
flex-direction: row;
align-items: center;
padding: 10px;
font-size: 25px;
font-weight: bold;
box-shadow: 0 3px 6px 0 #555;
`;
const SearchBox = styled.div`
display: flex;
flex-direction: row;
padding: 10px 10px;
border-radius: 6px;
margin-left: 20px;
width: 50%;
background-color: white;
`;
const SearchInput = styled.input`
color: black;
font-size: 16px;
font-weight: bold;
border: none;
outline: none;
margin-left: 15px;
`;
const MovieListContainer = styled.div`
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 30px;
gap: 25px;
justify-content: space-evenly;;
`;
class App extends Component {
constructor(props) {
super(props);
this.logOut = this.logOut.bind(this);
this.state = {
showCreatorBoard: false,
showAdminBoard: false,
currentUser: undefined,
timeoutId: "",
updateTimeoutId: ""
};
}
componentDidMount() {
const user = AuthService.getCurrentUser();
if (user) {
this.setState({
currentUser: user,
showCreatorBoard: user.roles.includes("ROLE_MODERATOR"),
showAdminBoard: user.roles.includes("ROLE_ADMIN"),
});
}
EventBus.on("logout", () => {
this.logOut();
});
}
componentWillUnmount() {
EventBus.remove("logout");
}
logOut() {
AuthService.logout();
this.setState({
showCreatorBoard: false,
showAdminBoard: false,
currentUser: undefined,
});
}
render() {
const { currentUser, showCreatorBoard, showAdminBoard} = this.state;
return (
<div>
<nav className="navbar navbar-expand navbar-dark bg-dark">
<Link to={"/"} className="navbar-brand">
Movie App
</Link>
<div className="navbar-nav mr-auto">
<li className="nav-item">
<Link to={"/home"} className="nav-link">
Home
</Link>
</li>
{showCreatorBoard && (
<li className="nav-item">
<Link to={"/mod"} className="nav-link">
Moderator Board
</Link>
</li>
)}
{showAdminBoard && (
<li className="nav-item">
<Link to={"/admin"} className="nav-link">
Admin Board
</Link>
</li>
)}
{currentUser && (
<li className="nav-item">
<Link to={"/user"} className="nav-link">
User
</Link>
</li>
)}
</div>
<Search />
{currentUser ? (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/profile"} className="nav-link">
{currentUser.username}
</Link>
</li>
<li className="nav-item">
<a href="/login" className="nav-link" onClick={this.logOut}>
LogOut
</a>
</li>
</div>
) : (
<div className="navbar-nav ml-auto">
<li className="nav-item">
<Link to={"/login"} className="nav-link">
Login
</Link>
</li>
<li className="nav-item">
<Link to={"/register"} className="nav-link">
Sign Up
</Link>
</li>
</div>
)}
</nav>
<div className="container mt-3">
<Switch>
<Route exact path={["/", "/home"]} component={Home} />
<Route exact path="/login" component={Login} />
<Route exact path="/register" component={Register} />
<Route exact path="/profile" component={Profile} />
<Route path="/films"
component={MovieList}
/>
<Route path="/user" component={BoardUser} />
<Route path="/creator" component={BoardCreator} />
<Route path="/admin" component={BoardAdmin} />
</Switch>
</div>
<MovieListContainer>
<MovieList></MovieList>
<MovieList></MovieList>
<MovieList></MovieList>
<MovieList></MovieList>
</MovieListContainer>
{ /*<AuthVerify logOut={this.logOut}/> */ }
</div>
);
}
}
搜索
function Search() {
const [searchQuery, setSearchQuery] = useState("");
const [timeoutId, updateTimeoutId] = useState();
const fetchData = async (searchString) => {
const response = await axios.get(`https://api.themoviedb.org/3/search/movie?api_key=f134dfeac1ebb17feefa58d7f94e94cd&language=en-US&query=${searchString}&page=1&include_adult=false`);
console.log(response);
};
const onTextChange = (e) => {
clearTimeout(timeoutId);
setSearchQuery(e.target.value);
const timeout = setTimeout(() => fetchData(e.target.value), 500);
updateTimeoutId(timeout);
};
return(
<div>
<SearchBox>
<SearchInput placeholder="SEARCH" value={searchQuery} onChange={onTextChange}></SearchInput>
</SearchBox></div>
);
}
export default App;
假设您使用的是 React 16 或更早版本,问题出在这一行:
const timeout = setTimeout(() => fetchData(e.target.value), 500);
直到最近,React 还试图重用事件对象,因此一旦同步代码完成 运行,它就会将 e.target 设置为 null。结果,到超时结束时,e.target
为空,因此 e.target.value
抛出异常。
选项 1:将值保存在局部变量中并使用它
const onTextChange = (e) => {
clearTimeout(timeoutId);
const value = e.target.value;
setSearchQuery(value);
const timeout = setTimeout(() => fetchData(value), 500);
updateTimeoutId(timeout);
};
选项 2:告诉 React 不要重用这个事件对象
const onTextChange = (e) => {
e.persist();
clearTimeout(timeoutId);
setSearchQuery(e.target.value);
const timeout = setTimeout(() => fetchData(e.target.value), 500);
updateTimeoutId(timeout);
};
更多信息,see this page