child 组件中未定义 react prop

react prop is undefined in child component

Main.js

import axios from 'axios'
import React, { Component, useEffect, useState } from 'react'
import { BrowserRouter as Router, Switch, Route} from "react-router-dom";
import Books from './Books'
import Navbar from './Navbar'
import AddBook from './AddBook';
import BookDetail from './BookDetail';

const Main = () => {
    let [selectedBook, setSelectedBook] = useState()  // Storing the data from Books.js
    let [books, setBooks] = useState([])

    useEffect(() => {
        axios.get('http://127.0.0.1:8000/api/get-books')
            .then(res => {
                setBooks(books = res.data)
            })
    })

    return (
        <Router>
            <div>
                <Navbar title={selectedBook}/> // is defined here <----
                <div className='container'>
                    <Switch>
                        <Route exact path='/' >
                            <Books books={books} onBookSelect={(book) => {setSelectedBook(book)} }/>  // Receiving the data from here
                        </Route>

                        <Route path='/add-book' >
                            <AddBook />
                        </Route>

                        <Route path={`/details`} >
                            <BookDetail bookId={selectedBook} /> // is undefined when passed here <----
                        </Route>
                    </Switch>
                </div>
            </div>
        </Router>
    )
}

export default Main

Books.js

import React, { Component, useState } from 'react'
import BookDetail from './BookDetail'

const Books = ({books, onBookSelect}) => {

    const sendBookId = e => {
        let bookId = e.target.value 
        onBookSelect('i am not undefined') // sending the data to Main.js
        setTimeout(function(){ window.location.href='http://localhost:3000/details' }, 10)
    }


    return (
        <div>
            <div className='books'>
                {books.map(book => (
                    <div className='book'> 
                        <h2>{book.name}</h2>
                        <p>Author: <a href='#'>{book.author}</a></p>
                        <button className="btn" value={book.id} onClick={sendBookId}>View Details</button>  // Getting the id from here
                    </div>
                ))}
            </div>
        </div>
    )
}

export default Books

BookDetail.js

import React, { useEffect } from 'react'
import axios from 'axios'
import { useState } from 'react'

const BookDetail = ({bookId}) => {

    return (
        <div>
            <p>book: {bookId}</p>  // bookId is undefined
        </div>
    )
}

export default BookDetail

样本来自 localhost:8000/api/get-books

{
    "id": 5,
    "name": "Book1",
    "author": "Author1",
    "content": "a normal book",
    "isbn": "235456",
    "passcode": "123",
    "created_at": "2021-07-12T16:29:47.114356Z",
    "pages": "3"
}

基本上,数据从Book.js发送到Main.js的parent组件,存储在selectedBook中,定义数据并显示在标题中,但是当我将它添加为道具并尝试从那里访问它时,它变得不确定,我做错了什么?

问题

感谢 Yoshi 首先指出,但您从主页导航到图书详细信息页面的方式存在问题。改变 window.location.href 对象实际上会重新加载页面和您的应用程序。由于 React 状态存在于内存中,因此它会在页面重新加载时丢失。

解决方案

使用 Router 上下文提供的 history 对象推送到新路由。由于您已经在使用功能组件,因此您可以从 react-router-dom 导入 useHistory React 挂钩并发出命令式导航。

import { useHistory } from 'react-router-dom';

...

const Books = ({ books, onBookSelect }) => {
  const history = useHistory(); // <-- access the history object from hook

  const sendBookId = (e) => {
    const bookId = e.target.value;
    onBookSelect(bookId);
    history.push("/details"); // <-- issue PUSH to route
  };

  return (
    <div>
      <div className="books">
        Books
        {books.map((book) => (
          <div className="book">
            <h2>{book.name}</h2>
            <p>
              Author: <a href="#">{book.author}</a>
            </p>
            <button className="btn" value={book.id} onClick={sendBookId}>
              View Details
            </button>
          </div>
        ))}
      </div>
    </div>
  );
};