开发者问题收集

TypeError:未定义不是一个对象(评估“movies.map”)

2021-10-01
2109

我正在使用 REACT 构建电影 API,当我在本地加载页面时,我不断收到错误消息“TypeError:undefined 不是对象(评估‘movies.map’)”。

import React from 'react';
    import axios from 'axios';
    import PropTypes from 'prop-types';
    import { Button, Card, CardDeck, Form, Row } from 'react-bootstrap';
    import './profile-view.scss';
    
    export class ProfileView extends React.Component {
      constructor() {
        super();
    
        this.state = {
          Name: null,
          Username: null,
          Password: null,
          Email: null,
          Birthdate: null,
          FavoriteMovies: [],
          validated: null,
          movies: [],
        };
      }
    
      componentDidMount() {
        const accessToken = localStorage.getItem('token');
        if (accessToken !== null) {
          this.getUser(accessToken);
        }
      }
    
    
      // get user method
      getUser(token) {
        const username = localStorage.getItem('user');
        axios.get(`https://nhas-flixdb-2021.herokuapp.com/users/${username}`, {
          headers: { Authorization: `Bearer ${token}` },
        })
          .then((response) => {
            this.setState({
              Name: response.data.Name,
              Username: response.data.Username,
              Password: response.data.Password,
              Email: response.data.Email,
              Birthdate: response.data.Birthdate,
              FavoriteMovies: response.data.FavoriteMovies,
            });
          })
          .catch(function (error) {
            console.log(error);
          });
      }
    
    
      removeFavoriteMovie() {
        const token = localStorage.getItem('token');
        const username = localStorage.getItem('user');
    
        
        axios.delete(`https://nhas-flixdb-2021.herokuapp.com/users/${username}/movies/${movies._id}`, {
            headers: { Authorization: `Bearer ${token}` },
          })
          
          .then(() => {
            alert('Movie was removed');
            this.componentDidMount();
          })
          .catch(function (error) {
            console.log(error);
          })
        // .then(() => window.location.reload());
      }
    
      handleUpdate(e, newName, newUsername, newPassword, newEmail, newBirthdate) {
        this.setState({
          validated: null,
        });
    
        const form = e.currentTarget;
        if (form.checkValidity() === false) {
          e.preventDefault();
          e.stopPropagation();
          this.setState({
            validated: true,
          });
          return;
        }
        e.preventDefault();
    
        const token = localStorage.getItem('token');
        const username = localStorage.getItem('user');
    
        axios.put(`https://nhas-flixdb-2021.herokuapp.com/users/${username}`, {
          headers: { Authorization: `Bearer ${token}` },
          data: {
            Name: newName ? newName : this.state.Name,
            Username: newUsername ? newUsername : this.state.Username,
            Password: newPassword ? newPassword : this.state.Password,
            Email: newEmail ? newEmail : this.state.Email,
            Birthdate: newBirthdate ? newBirthdate : this.state.Birthdate,
          },
        })
          .then((response) => {
            alert('Saved Changes');
            this.setState({
              Name: response.data.Name,
              Username: response.data.Username,
              Password: response.data.Password,
              Email: response.data.Email,
              Birthdate: response.data.Birthdate,
            });
            localStorage.setItem('user', this.state.Username);
            window.open(`/users/${username}`, '_self');
          })
          .catch(function (error) {
            console.log(error);
          });
      }
      setName(input) {
        this.Name = input;
      }
    
      setUsername(input) {
        this.Username = input;
      }
    
      setPassword(input) {
        this.Password = input;
      }
    
      setEmail(input) {
        this.Email = input;
      }
    
      setBirthdate(input) {
        this.Birthdate = input;
      }
    
      handleDeleteUser(e) {
        e.preventDefault();
    
        const token = localStorage.getItem('token');
        const username = localStorage.getItem('user');
    
        axios.delete(`https://nhas-flixdb-2021.herokuapp.com/users/${username}`, {
          headers: { Authorization: `Bearer ${token}` },
        })
          .then(() => {
            localStorage.removeItem('user');
            localStorage.removeItem('token');
            alert('Your account has been deleted.');
            window.open(`/`, '_self');
          })
          .catch((e) => {
            console.log(e);
          });
      }
    
      render() {
        const { FavoriteMovies, validated} = this.state;
        const { movies } = this.props;
        
        return (
          <Row className="profile-view">
            <Card className="profile-card">
              <h1 className="text-center">Your Account</h1>
              <h2>Your Favorites Movies</h2>
              <Card.Body>
                {FavoriteMovies.length === 0 && <div className="text-center">Empty.</div>}

我不确定 movies.map 发生了什么。我查了一下可能是什么问题,但没有找到。除了此部分,我网页上的其他所有内容都正常工作。

<div className="favorites-movies ">
              {FavoriteMovies.length > 0 &&
                movies.map((movies) => {
                  if (movies._id === FavoriteMovies.find((favMovie) => favMovie === movies._id)) {
                    return (
                      <CardDeck className="movie-card-deck">
                        <Card className="favorites-item card-content" style={{ width: '16rem' }} key={movies._id}>
                          <Card.Img style={{ width: '18rem' }} className="movieCard" variant="top" src={movies.ImagePath} />
                          <Card.Body>
                            <Card.Title className="movie-card-title">{movies.Title}</Card.Title>
                            <Button size='sm' className='profile-button remove-favorite' variant='danger' value={movies._id} onClick={(e) => this.removeFavoriteMovie(e, movies)}>
                              Remove
                            </Button>
                          </Card.Body>
                        </Card>
                      </CardDeck>
                    );
                  }
                })}
            </div>
          </Card.Body>
          <h3 className="section">Update Profile</h3>
          <Card.Body>
            <Form noValidate validated={validated} className="update-form" onSubmit={(e) => this.handleUpdate(e, this.Name, this.Username, this.Password, this.Email, this.Birthdate)}>

              <Form.Group controlId="formName">
                <Form.Label className="form-label">Name</Form.Label>
                <Form.Control type="text" placeholder="Change Name" onChange={(e) => this.setName(e.target.value)} />
              </Form.Group>

              <Form.Group controlId="formBasicUsername">
                <Form.Label className="form-label">
                  Username<span className="required">*</span>
                </Form.Label>
                <Form.Control type="text" placeholder="Change Username" onChange={(e) => this.setUsername(e.target.value)} />
              </Form.Group>

              <Form.Group controlId="formBasicPassword">
                <Form.Label className="form-label">
                  Password<span className="required">*</span>
                </Form.Label>
                <Form.Control type="password" placeholder="New Password" onChange={(e) => this.setPassword(e.target.value)} />
              </Form.Group>

              <Form.Group controlId="formBasicEmail">
                <Form.Label className="form-label">
                  Email<span className="required">*</span>
                </Form.Label>
                <Form.Control type="email" placeholder="Change Email" onChange={(e) => this.setEmail(e.target.value)} />
              </Form.Group>

              <Form.Group controlId="formBasicBirthday">
                <Form.Label className="form-label">Birthdate</Form.Label>
                <Form.Control type="date" placeholder="Change Birthdate" onChange={(e) => this.setBirthdate(e.target.value)} />
              </Form.Group>

              <Button variant='danger' type="submit">
                Update
              </Button>

              <h3>Delete your Account</h3>
              <Card.Body>
                <Button variant='danger' onClick={(e) => this.handleDeleteUser(e)}>
                  Delete Account
                </Button>
              </Card.Body>
            </Form>

          </Card.Body>
        </Card>
      </Row >
    );
  }
}

ProfileView.propTypes = {
  user: PropTypes.shape({
    FavoriteMovies: PropTypes.arrayOf(
      PropTypes.shape({
        _id: PropTypes.string.isRequired,
        Title: PropTypes.string.isRequired,
      })
    ),
    Username: PropTypes.string.isRequired,
    Email: PropTypes.string.isRequired,
    Birthdate: PropTypes.string,
  }),
};
2个回答

您没有将 movies prop 传递给组件,因此 movies 未定义,而 undefined 没有 map 方法。

我不清楚您的两个代码示例之间的关系,但是……

您有三个名为“movies”的独立变量。

  • 一个通过 this.state = { movies: []
  • 处于状态中
  • 另一个从 props 获得: const { movies } = this.props
  • 第三个在您的 map 函数中: movies.map((movies) => {})`

这是我们对错误感兴趣的第二个。 (第一个从未被引用,第三个造成了混淆,但没有实际问题。)

为了使 this.props.movi​​es 成为一个数组,组件必须将其作为 prop 接收。

这是您的组件的简化版本,已精简以隔离 movies.map 问题:

class MyComponent extends React.Component {
  render () {
    const {movies} = this.props;
    return (
      movies.map(m => <li>{m}</li>);
    );
  }
}'

如果您将数组作为 prop 传递,则一切都很好:

const movieArray = ['x', 'y', 'z'];

<MyComponent movies={movieArray} />

如果您省略 prop,它会爆炸,因为 this.props.movi​​es 未定义:

// blows up because this.props.movies isn't
// defined so you can't call this.props.movies.map

<MyComponent />

我不知道您是否有意使用 this.props.movi​​es 而不是 this.state.movi​​es ,但这就是它爆炸的原因。

您可以使用 可选链接

movies?.map?.(m => {})

使用此语法,如果 movies 未定义或者没有 map 方法,它将不会尝试调用它并且不会引发错误。

ray
2021-10-01

您破坏了组件的核心原则之一,该原则与 Concert 是分开的,您当前的组件负责获取数据以及渲染数据。此组件应仅获取数据,而其他组件应渲染数据,但最简单的解决方法是验证您的数据是否存在(如果存在),则通过它进行映射

{FavoriteMovies.length > 0 && movies &&  movies.map((movies)}
JS Disciple
2021-10-02