【问题标题】:react prop is undefined in child componentreact prop 在子组件中未定义
【发布时间】:2021-07-13 18:15:34
【问题描述】:

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 并存储在 selectedBook 中的,数据被定义并显示在标题中,但是当我将其作为道具添加到尝试从那里访问它变得未定义,我做错了什么?

【问题讨论】:

  • 我看不出这段代码有任何明显的问题。您能否添加一个示例 http://127.0.0.1:8000/api/get-books 响应以便我们可以尝试重现该问题,或者您可以尝试使用我们可以检查和检查的模拟响应创建一个 running 代码框现场调试?
  • 我添加了示例!
  • 在您的代码中,没有任何迹象表明您实际上是如何导航到 /details?
  • 是的,我删除了那部分,但我现在重新添加了它(它位于 Books.js 的 sendBookId 函数中)
  • 哦,是的,我现在看到您的导航方式的更新/编辑问题。使用Link 组件或使用react-router-dom 中的history 对象,就像我必须添加以推送到新路线一样。昨晚已经很晚了,但我今天也注意到Main 中的useEffect 钩子缺少依赖数组,因此会导致大量不必要的数据获取、状态更新和重新渲染。

标签: reactjs react-props


【解决方案1】:

问题

感谢 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>
  );
};

【讨论】:

  • 它确实有效,因为标题没有消失,但由于某种原因它在 BookDetail 中仍未定义......让我在这里添加它
  • @Luna 书名?它在沙箱中工作。你能澄清什么对你来说还没有定义吗?随意分叉我的沙箱并应用您的代码,以便我们看看可能有什么不同。
  • 它工作了,我将反引号从 {/details} 删除到 {"/details"} 并且由于某种原因它现在工作了,非常感谢你们!
猜你喜欢
  • 2018-09-14
  • 2021-10-15
  • 2019-01-13
  • 1970-01-01
  • 2020-11-11
  • 2018-07-09
  • 1970-01-01
  • 2019-06-20
  • 2021-04-06
相关资源
最近更新 更多