【问题标题】:Child components are getting different state versions from Parent state during the same render子组件在同一渲染期间从父状态获得不同的状态版本
【发布时间】:2020-06-15 03:40:57
【问题描述】:

我在使用 React 时遇到了这个非常令人困惑的问题,因此非常感谢任何帮助/见解!在我的应用程序的身份验证组件(父组件)中,我根据当前应用程序用户是否具有管理员权限来设置状态。然后,我将此管理状态作为道具传递给三个不同的子组件({News}、{Resources} 和 {AdminDashboard},所有这些组件的呈现方式都不同,具体取决于用户的管理状态。

这是令人困惑的部分。所有三个子组件都是在同一个渲染周期内创建的。然而,这三个子组件中的两个正在接收准确且最新的父状态(因此被传递到最新的道具),但第三个似乎正在接收过时的状态值(初始状态null,而不是 true 或 false,因为其他两个正在接收),导致传递给它的 props 不准确。我可以通过父组件和子组件上的各种 console.logs 看到对此的确认。我一定忽略了一些东西,但我想不通,因为我认为如果发生重新渲染,状态会被统一推送到所有需要它的子组件上。我正在使用确切的代码通过各自的路线创建所有三个组件。这是相关代码的骨架/模型(为简洁起见,排除了一些导入、声明等):

/* AuthWrapper (PARENT component) */

class AuthWrapper extends Component {
 state = {
    admin: null,
  };

componentDidMount() {
 // performs the necessary server-side checks then sets state, ex: if user is an admin then

 this.setState({
   admin: true
 });
}

render() {
 return (

// some other components 

  // News and Resources components are receiving correctly updated props from the state, and are rendering 
  // as expected. Logging their props.admin reveals a true or false value (which is the desired outcome)

  <Route path="/news" render={props => <News {...props} admin={this.state.admin} />} />
  <Route path="/resources" render={props => <Resources {...props} admin={this.state.admin} />} />

// AdminDashboard, on the other hand, is receiving a props admin value of '', as revealed when logging its props.admin property
// This makes the component treat every user like they're not an admin, even if they are. 
// This is not the expected outcome, since this component is being rendered by the same state change as the others

  <Route path="/admindashboard" render={props => <AdminDashboard {...props} admin={this.state.admin} />} />

// some other components 
 )
}


/* AdminDashboard (CHILD component) */

import React, { Component } from "react";
import { Redirect } from "react-router-dom";
import firebase from "../firebase/firebase";
import "firebase/functions";

class AdminDashboard extends Component {
  state = {
    email: null
  };

  handleChange = e => {
    this.setState({
      [e.target.id]: e.target.value
    });
  };

  // add admin cloud function
  handleSubmit = e => {
    e.preventDefault();
    const functions = firebase.functions();
    const addAdminRole = functions.httpsCallable("addAdminRole");
    addAdminRole({ email: this.state.email }).then(result => {
      console.log(result);
    });
  };

  render() {
    // this console.log is returning null, but should be true or false (as it is in other child components)
    console.log(this.props.admin); 
    return this.props.admin ? (
      <div className="container form-container">
        <form
          onSubmit={this.handleSubmit}
          className="center-align admin-actions"
          style={({ margin: "40px auto" }, { maxWidth: "300px" })}
        >
          <input
            onChange={this.handleChange}
            type="email"
            placeholder="User email"
            id="email"
            required
          />
          <button className="btn-small yellow darken-2 z-depth-0">
            Make admin
          </button>
        </form>
      </div>
    ) : (
      <Redirect to="/" />
    );
  }
}

export default AdminDashboard;




我一直在摸索这个问题,但无济于事!再次感谢任何人对此的见解,并提前感谢!

PS:我知道使用像 Redux 这样的状态管理工具可能会最大限度地减少此类问题,但目前我仍在尝试真正了解 React 的基础知识以及状态如何传输和传递等。 .

【问题讨论】:

  • 一个建议,在定义尚未确定的状态值时使用null,例如admin 情况(当前使用空字符串)。 React 总是需要一个顶级元素;这只是复制/粘贴,还是您的组件渲染缺少包装元素?除此之外,它看起来应该可以工作,你能分享AdminDashboard的内容吗?
  • 注意,感谢您的建议,知道这非常有用。不,缺少包装元素只是您所说的复制/粘贴,所有内容都正确嵌套并且没有语法/运行时错误或来自控制台的投诉。我已经更新了代码,希望让它更清晰一些,并在底部包含了完整的 AdminDashboard 代码。基本上,如果用户是管理员,我应该会看到正在呈现的管理仪表板,如果不是,则被重定向到主页。目前,由于这个问题,条件渲染总是触发 falsy 选项并重定向
  • 我能想到的 News and Resources 工作和 AdminDashboard 不工作之间的唯一区别是,对于 AdminDashboard,Route 路径和您尝试更新的道具是相同的。我不明白为什么这应该是一个问题,但也许有某种干扰?如果将路径更改为path='./admindashboard',会发生什么情况?
  • @Seth 答案是关键。在您的情况下,仅使用收到的 admin 道具。如果需要设置一个子 admin 属性(因为它与父属性不同但依赖于它),那么当父属性更改时,您需要在 componentDidUpdate 中更新它。
  • @Seth 非常感谢您的建议,不幸的是问题仍然存在。产生差异的原因是因为最初AdminDashboard被简单地称为Admin,但是更改路径似乎并没有解决它

标签: reactjs react-router react-props react-component react-state


【解决方案1】:

我认为你的问题在这里:

/* AdminDashboard (CHILD component) */

  componentDidMount() {
    this.setState({ admin: this.props.admin });
  }

当 AdminDashboard 挂载时,它正在从父级读取 null。但在 AdminDashboard 中,this.state.admin 永远不会更新为非空值。您需要在 AdminDashboard 中添加一个componentDidUpdate 才能完成这项工作。

为什么您仍然需要 AdminDashboard 中的this.state.admin?只需使用this.props.admin,您的价值就会适当地向下转移。所以在我们的渲染方法中:

render() {

    console.log(this.props.admin); 
    return this.props.admin ? ( 
       ...
    )

【讨论】:

  • 我一直在删除和取消删除这个答案,因为我不确定它是否正确,哈哈。我觉得它没有解决“this console.log is returning null, but should be true or false (as it is in other child components)”的问题......似乎Daniel Cassar已经修改了他的代码以包含这个答案的建议。
  • 谢谢Seth,我粘贴了一些可能具有误导性的错误代码,我很抱歉......我现在已经相应地更新了
猜你喜欢
  • 2021-04-06
  • 1970-01-01
  • 2020-12-30
  • 2016-04-22
  • 2017-02-03
  • 2020-07-18
  • 2021-06-02
  • 2016-01-25
  • 2019-09-21
相关资源
最近更新 更多