【问题标题】:Forwarding props from parent to child component将 props 从父组件转发到子组件
【发布时间】:2021-03-23 06:00:18
【问题描述】:

我有 2 个帖子组件列表,当单击明信片上的链接时,我正在进入帖子。 我无法访问子组件中的 props.postDetails。当我控制台记录道具时,我有 {history: {…}, location: {…}, match: {…}, staticContext: undefined} 只有这个没有 props.postDetails。 有人可以帮忙吗?

父组件的代码是:

mport {useState, useEffect} from 'react';
import {BrowserRouter as Router, Switch, Route, Link, withRouter} from "react-router-dom";
import logo from "./assets/images/logo.jpg";
import Post from './Post';


const Home = () => {
    const [posts, setPosts] = useState([]);

    useEffect(() => {
        getResults();
    },[]);

    const getResults =() => {
        fetch("https://blog-d8b04-default-rtdb.europe-west1.firebasedatabase.app/posts.json")
            .then(response => response.json())
            .then(data => {setPosts(data)});
    }

    const postsArr = [];
    Object.values(posts).forEach((post, key) => {
        postsArr.push(post);
    });

    return(
        <div>
            <div className="container-fluid">
                <div className="row">
                    <div className="posts-container col-md-12">
                        <div className="row">
                            {
                                postsArr.map((post, key) => (
                                    <div className="col-md-4">
                                        <Link to={`/post/${key}`} >
                                            <div className="pic-wrapper">
                                                <img className="img-fluid" src={post.pic} alt={post.title}/>
                                            </div>
                                            <h4>{post.title}</h4>
                                            <Post postDetails={post}/>
                                        </Link>
                                    </div>
                                ))
                            }
                        </div>
                    </div>
                </div>
            </div>
        </div>
    )
}

子组件代码:

import {withRouter} from "react-router-dom";


const Post = (props) => {
    const {pic, title, author, description} = props.postDetails;
    return(
        <div className="container">
            <div className="pic-wrapper">
                <img className="img-fluid" src={pic} alt={title}/>
            </div>
            <h4>{title}</h4>
            <p>{author}</p>
        </div>
    )
}

export default withRouter(Post);

【问题讨论】:

  • 是否有理由包装 Post 组件'withRouter'?看起来 withRouter HOC 没有从父级传递道具。
  • 同样没有 HOC withRouter 不转发,同样的事情。
  • 是的,如果没有 HOC,您将无法获得位置、匹配、历史道具,但是,如果我正确阅读您的代码,您似乎不需要用路由器包装您的明信片.如果您希望用户单击卡片导航到详细信息页面,那么您需要两条路线;主页和帖子详细信息。
  • 在提供的 sn-p 中,我绝对没有理由不定义 props.postDetails。你确定你引用了正确的组件吗?您能否提供一个重现此问题的 running 代码框? postsArr 有什么意义?似乎您可以轻松地直接映射 posts 状态。 withRouter 似乎也同样没用,因为它似乎没有 Post 引用任何路由道具。这就是你真实的、完整的代码吗?

标签: javascript reactjs


【解决方案1】:

问题

好吧,我开始怀疑了。您在不止一个地方渲染 Post 组件。

这里的问题是,在Home.js 中,您传递了一个postDetails 道具,(&lt;Post postDetails={post.pic} /&gt;),但在app.js 中,您只传递了来自Route 的路线道具,(&lt;Route path="/post/:postId" exact strict component={Post} /&gt;)。 这个 Post 组件是触发错误的组件。

解决方案

一个简单的解决方案是简单地将post 数据与路由转换一起传递。

<Link
  to={{
    pathname: `/post/${key}`,
    state: {
      post
    }
  }}
>
  ...
  <Post postDetails={post.pic} />
</Link>

并在Post中访问接收端的路由状态。尝试先从 props 中读取帖子详细信息,如果它们是错误的(null 或未定义),则假定它是在路由状态中传递并在那里访问它。

const Post = (props) => {
  const { state } = props.location;
  const { pic, title, author, description } = props.postDetails ?? state.post;
  return (
    <div className="container">
      <div className="pic-wrapper">
        <img className="img-fluid" src={pic} alt={title} />
      </div>
      <h4>{title}</h4>
      <p>{author}</p>
    </div>
  );
};

当然还有空间让它更健壮一些,但这是一个好的开始。

补充建议

您可以将响应数据保存到状态。这样就省去了每次组件重新渲染时都进行转换的不必要步骤。

const getResults = () => {
  setLoading(true);
  fetch(
    "https://blog-d8b04-default-rtdb.europe-west1.firebasedatabase.app/posts.json"
  )
    .then((response) => response.json())
    .then((data) => {
      setPosts(Object.values(data));
      setLoading(false);
    });
};

然后照常映射。确保将 React 键放在 outer-most 映射元素上,在您的情况下为 div

{posts.map((post, key) => (
  <div className="col-md-4" key={key}>
    ...
  </div>
))}

演示

【讨论】:

  • 感谢@Dreew Reese,也许适合从 App.js 加载数据 - 使用 useEffect 挂钩,而不是从那里将道具转发到 Home 路由。
  • @Ivana 是的,IMO 一个更合适的解决方案是将帖子存储在一个共同的祖先中,以供所有可以访问它们的组件使用。例如,React 上下文将有助于这项工作,它是轻量级的。
  • @Dreew Reese,关于您建议从 App.js 加载数据,然后您打算将数据转发到子组件 - 到 Post.js,就像在此示例中与 /post/${key},状态:{ post } }} >?或者你的意思是不同的?
  • @Ivana 您好,抱歉,您指的是哪个建议?
  • 我知道您建议在 App.js 中获取数据,然后将数据转发给子组件,但我很好奇您将数据转发给子组件的方式?正如您在示例中所写的那样,使用 的“to”属性,因为我们正在遍历帖子数组,或者如何?
【解决方案2】:

这确实是一种预期的行为,因为您实际上正在映射看起来是一个空数组 - 请参阅postArr;在您第一次渲染时,它会生成一个空数组,因为这不是一个状态,所以它永远不会使用适当的道具重新渲染您的子组件。

我真的不明白你为什么要获取数据,将它们设置为posts useState,然后将它们复制到普通变量;相反,请删除您的 postArr 并在地图上直接将其替换为您的 posts

由于这是一个状态,react 将监听更改并相应地重新渲染,从而解决您的问题

【讨论】:

  • postsArr 在每个渲染周期计算,因此当posts 状态更新并触发重新渲染时,postsArr 也会更新。
  • 实际上你是对的 - 所以@Ivana,如果你在Post 组件之前添加一个控制台日志会怎样?此时post 会返回什么?
猜你喜欢
  • 2020-07-26
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
  • 1970-01-01
  • 2020-01-12
  • 2020-09-28
  • 2018-05-25
相关资源
最近更新 更多