Дочерние компоненты получают разные версии состояния из родительского состояния во время одного и того же рендеринга - PullRequest
0 голосов
/ 02 марта 2020

Я столкнулся с этой очень запутанной проблемой с React, поэтому любая помощь / понимание будет с благодарностью! В компоненте Auth моего приложения (родительский компонент) я устанавливаю состояние в зависимости от того, имеет ли текущий пользователь приложения права администратора или нет. Затем я передаю это состояние администратора в качестве подпорки трем различным дочерним компонентам ({News}, {Resources} и {AdminDashboard}, каждый из которых отображается по-разному в зависимости от состояния администратора пользователя.

Вот сбивающая с толку часть. Все три дочерних компонента создаются в одном и том же цикле рендеринга. Однако два из этих трех дочерних компонентов получают точное и обновленное родительское состояние (и, следовательно, передаются актуальным реквизитам), но третий по-видимому, получает устаревшее значение состояния (начальное состояние null, а не true или false, как получают два других), что приводит к тому, что ему передаются неточные реквизиты. Я вижу подтверждение этому через различные console.logs как на родительском, так и на дочернем компонентах. Я, должно быть, что-то упускаю, но не могу понять, так как думал, что если произойдет повторный рендеринг, состояние будет равномерно распределено по всем дочерним компонентам, которым это требуется. И я использую точный код для создания всех трех компоненты через их соответствующие маршруты. Вот скелет / макет рассматриваемого кода (за исключением краткости импорта, объявлений и т. Д. c ...):

/* 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 и то, как состояние передается и передается, et c ...

1 Ответ

0 голосов
/ 02 марта 2020

Я думаю, что ваша проблема здесь:

/* AdminDashboard (CHILD component) */

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

Когда монтируется AdminDashboard, он читает null от родителя. Но в AdminDashboard this.state.admin никогда не обновляется как не ноль. Вам нужно добавить componentDidUpdate из AdminDashboard, чтобы эта работа работала.

Зачем вам все-таки нужно this.state.admin из AdminDashboard? Просто используйте this.props.admin, и ваше значение должно соответственно уменьшиться. Итак, в нашем методе рендеринга:

render() {

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