web-dev-qa-db-ja.com

なぜReactコンポーネントが2回レンダリングされるのですか?

私のReactコンポーネントが2回レンダリングされている理由がわかりません。だから私はFirestoreで検索できるように、paramsから電話番号を引き出して状態に保存しています。 1回目は電話番号とゼロポイントをレンダリングし、2回目はすべてのデータが正しく表示されます。

class Update extends Component {
constructor(props) {
    super(props);
    const { match } = this.props;
    this.state = {
        phoneNumber: match.params.phoneNumber,
        points: 0,
        error: ''
    }
}

getPoints = () => {
    firebase.auth().onAuthStateChanged((user) => {
        if(user) {
            const docRef = database.collection('users').doc(user.uid).collection('customers').doc(this.state.phoneNumber);
            docRef.get().then((doc) => {
                if (doc.exists) {
                const points = doc.data().points;
                this.setState(() => ({ points }));
                console.log(points);
                } else {
                // doc.data() will be undefined in this case
                console.log("No such document!");
                const error = 'This phone number is not registered yet...'
                this.setState(() => ({ error }));
                }
                }).catch(function(error) {
                console.log("Error getting document:", error);
                });
        } else {
            history.Push('/')
        }
    });
}

componentDidMount() {
    if(this.state.phoneNumber) {
        this.getPoints();
    } else {
        return null;
    }
}

render() {
    return (
        <div>
            <div>
                <p>{this.state.phoneNumber} has {this.state.points} points...</p>
                <p>Would you like to redeem or add points?</p>
            </div>
            <div>
                <button>Redeem Points</button>
                <button>Add Points</button>
            </div>
        </div>
    );
  }
}

export default Update;
7
Raul Sanchez

Reactは、getPointsが非同期操作を完了する前にコンポーネントをレンダリングしています。

したがって、最初のrenderpointsの初期状態を示し、これは0、その後componentDidMountが呼び出され、非同期操作をトリガーします。
非同期操作が完了し、状態が更新されると、新しいデータで別のrenderがトリガーされます。

必要に応じて、ローダーまたはデータがフェッチされており、まだ表示する準備ができていないことを示すインジケータを 条件付きレンダリング で表示できます。

isFetchingなどの別のブールキーを追加し、サーバーを呼び出すときにtrueに設定し、データを受信するときにfalseに設定します。

レンダーは次のようになります。

render() {
  const {isFetching} = this.state;
  return (
    <div>
    {
        isFetching ? <div>Loading...</div> : (
      <div>
        <p>{this.state.phoneNumber} has {this.state.points} points...</p>
            <p>Would you like to redeem or add points?</p>
        </div>
        <div>
                <button>Redeem Points</button>
                <button>Add Points</button>
            </div>
        </div>  
      )
    }
  );
}
8
Sagiv b.g