组件在重新加载时会丢失状态数据

时间:2018-10-12 23:38:45

标签: reactjs firebase firebase-realtime-database

我正在构建一个基本的表单设置,但是需要获取更改之前用户的数据,以便他们可以从该数据进行编辑。首次加载页面时,一切正常,但是刷新页面(F5)后,我得到了错误:Unhandled Rejection (TypeError): Cannot read property 'userFirstName' of null。我第二次刷新页面时没有抓住userId。如果我离开该页面并转到另一个页面并返回,它将重新加载。如何使页面始终在刷新页面时重新获取数据?

我正在使用React.js,Firebase和React-router

Settings.js:

import React, { Component } from 'react';
import fire from '../../config/Fire.js';

export default class Settings extends Component {
    constructor(props) {
        super(props)
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.update = this.update.bind(this);

        this.userDatabase = fire.database().ref().child('users');
        this.state = {
            userId: this.props.user.uid,
            userFirstName: '',
        };
      }

        componentWillMount(){
                fire.database().ref('/users/' + this.state.userId).once('value').then(function(snapshot) {
                    var first_name = (snapshot.val().userFirstName);

                    this.setState({
                    userFirstName: first_name,
                    })
                }.bind(this));
        }

      handleChange(e) {
          this.setState({ [e.target.name]: e.target.value });
      }

      handleSubmit(e) {
          e.preventDefault();
      }

      update(e){
          e.preventDefault();
          //update here
          fire.auth().createUserWithEmailAndPassword(this.state.email, this.state.password).then((u)=>{ this.props.history.push('/about') }).catch((error) => {
              alert(error);
              });
      }

    render() {
        return (
            <div className="m-container">
                <h1>Hello, {this.state.userFirstName}</h1>
                <hr/>
                <p>Here are your settings details:</p>
                <label for="first-name">First Name: </label>
                <br/>
                <input 
                    value={this.state.userFirstName} 
                    onChange={this.handleChange} 
                    type="text" 
                    name="first-name" 
                    id="first-name" 
                    placeholder={this.state.userFirstName}
                    />
                <br/>
                <br/>
                <button 
                    type="submit" 
                    className="m-btn" 
                    onClick={this.signup}>Submit</button>
                &nbsp;
            </div>
        );
    }
}

Index.js(将userId作为道具传递给页面的路由):

import React, { Component } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';

import Home from './main/Home';
import About from './main/About';
import LoginContainer from '../components/LoginContainer';
import RegisterContainer from '../components/RegisterContainer';
import Resolved from './main/Resolved';
import Settings from './main/Settings';

export default class Routes extends Component {

    render() {
        return (
        <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/about" exact component={About} />
            <Route path="/register" render={()=> <RegisterContainer user={this.props.user} />} />
            <Route path="/login" render={()=> <LoginContainer user={this.props.user} />} />

            <Route path="/resolved" exact render={()=>(
                this.props.user ? (<Resolved user={this.props.user} />) : 
                (alert("You must log in to visit this page."), (<Redirect to="/login"/>))
            )} />
            <Route path="/account/settings" exact render={()=>(
                this.props.user ? (<Settings user={this.props.user} />) : 
                (alert("You must log in to visit this page."), (<Redirect to="/login"/>))
            )} />


        </Switch>
        );
    }

};

2 个答案:

答案 0 :(得分:1)

您应该在import CareKit import SwiftyJSON enum ActivityType: String { case Intervention case Assessment } enum ScheduleType: String { case Weekly case Daily } enum StepFormat : String { case Scale case Quantity } protocol Activity { var identifier : String { get set} var groupIdentifier : String { get set} var title : String { get set} var colour : UIColor? { get set} var text : String { get set} var startDate : Date { get set} var schedule : [NSNumber] { get set} var scheduleType : ScheduleType { get set} var instructions : String? { get set} var imageURL : NSURL? { get set} var activityType: ActivityType { get set} var medication : Medication? { get set} init() init(json: JSON) func createCareKitActivity() -> OCKCarePlanActivity } extension Activity { // A mutating function to allow Acticities or Assessments to intialiser base properties mutating func parseActivityFields(json: JSON) { self.identifier = json["identifier"].string! self.groupIdentifier = json["group_identifier"].string! self.title = json["title"].string! self.text = json["text"].string! let colourString = json["color"].string! self.colour = UIColor.colorWithString(colourString) if let instructionString = json["instructions"].string { self.instructions = instructionString } if let imageString = json["imageURL"].string { let componentsOfString = imageString.components(separatedBy: ".") if let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1]){ self.imageURL = NSURL(fileURLWithPath: pathForResource) } } self.startDate = dateFromString(string: json["startdate"].string!)! self.scheduleType = ScheduleType(rawValue: json["scheduletype"].string!)! self.schedule = json["schedule"].string!.components(separatedBy: ",").map ( { NSNumber(value: Int32($0)!) }) if let medication = json["medication"].string, let medicationImageString = json["medicationimage"].string { let componentsOfString = medicationImageString.components(separatedBy: ".") let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1]) self.medication = Medication.init(medication: medication, imageURL: NSURL.init(fileURLWithPath: pathForResource!)) } } init(json: JSON) { self.init() self.parseActivityFields(json: json) } func createCareKitActivity() -> OCKCarePlanActivity{ //creates a schedule based on the internal values for start and end dates let startDateComponents = NSDateComponents(date: self.startDate, calendar: NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)! as Calendar) let activitySchedule: OCKCareSchedule! switch self.scheduleType { case .Weekly : activitySchedule = OCKCareSchedule.weeklySchedule(withStartDate: startDateComponents as DateComponents, occurrencesOnEachDay: self.schedule) case .Daily: activitySchedule = OCKCareSchedule.dailySchedule(withStartDate: startDateComponents as DateComponents, occurrencesPerDay: self.schedule[0].uintValue) } let activity = OCKCarePlanActivity.intervention( withIdentifier: identifier, groupIdentifier: nil, title: title, text: text, tintColor: colour, instructions: instructions, imageURL: imageURL as? URL, schedule: activitySchedule, userInfo: ["medication": medication], optional: false) return activity } } 中调用Firebase连接,但不要在构造函数中调用。您可以阅读何时使用React Lifecycles的详细信息。即使它已经过时(未发表16条文章),它也是一个很棒的资源。 https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1

componentDidMount

答案 1 :(得分:0)

已解决以下问题:https://javebratt.com/firebase-user-undefined/

进行了异步调用,因为uid在获取数据之前暂时为空,并且触发了错误。只需等待数据加载就可以消除错误。另外,我正在通过fire.auth().currentUser.uid来获取uid。

我在Settings.js中更改的代码:

  componentDidMount(){
    // Asynchronous call fixes uid being null on reload
    fire.auth().onAuthStateChanged( user => {
        if (user) { 
            fire.database().ref('/users/' + fire.auth().currentUser.uid).once('value').then(function(snapshot) {
                this.setState({
                  userFirstName: (snapshot.val().userFirstName),
                  userLastName: (snapshot.val().userLastName),
                  userEmail: (snapshot.val().userEmail),
                  userPhone: (snapshot.val().userPhone),
                  userAddress: (snapshot.val().userAddress),
                  userZip: (snapshot.val().userZip),
                  userProfilePicUrl: (snapshot.val().userProfilePicUrl)
                })
              }.bind(this));          
         }
      });