React客户端componentDidMount无法正常工作(服务器端呈现)

时间:2017-08-24 14:21:07

标签: javascript node.js reactjs client-side server-rendering

Hello Stackoverflow社区

如果我的解释不够明确,请提前抱歉

当用户直接输入网址时。服务器发出请求,获取相应的数据并呈现屏幕。这完美地运作

当用户点击某个链接时,该页面会假设切换并呈现新组件,并通过componentDidMount从服务器获取相应的数据并保存到状态但由于某种原因,数据不会显示在页面上

当我运行下面的代码时,console.log('2')出现在console.log('1')之前,这意味着在填充获取的数据之前,状态首先呈现为未定义

它看起来像一个异步问题,但我不知道我的方式,这不应该是这种情况,因为它适用于普通的客户端应用程序

但即使事件的顺序失真,应用程序也应该在状态发生变化时重新呈现。

News.js

import React from 'react';
import NewsList from './newslist';
import 'es6-promise'
import 'isomorphic-fetch';

class News extends React.Component {
  constructor(props){
    super(props)

    let initialData;

    if(props.staticContext){
      initialData = props.staticContext.initialData

    } else if (typeof window !== 'undefined') {
      initialData = window.__initialData__
      delete window.__initialData__
    }

    this.state = {news: initialData }
  }

  componentDidMount() {
    News.requestInitialData().then(data => {
      console.log('1 ' + data)                           <------- console log 1
    return this.setState({ news: data })
    });
    console.log('2 ' + this.state)                       <------- console log 2
  }

  static requestInitialData() {
    return fetch('http://localhost:3000/api/data')
    .then(response => response.json())
    .catch(err => console.log(err))
  }

  render() {
    return (
      <div className="App">
        <NewsList news={this.state.news} />
      </div>
    );
  }
}

module.exports = News

NewsList.js

import React, { Component } from "react";

export default class NewsList extends Component {
  constructor(props){
    super(props)

    // const data = (this.props.news) ? this.props.news : '';
    this.state = {news : this.props.news,
                  sortOrder: 'ascending'}
  }

  sortOrder(order, event) {
    event.preventDefault();
    const data = Object.assign([], this.state.news)
    let data2;

    if (order === 'ascending') {
      data.sort( (a,b) => a.id - b.id )
      data2 = 'ascending'
    }
    else if (order === 'descending') {
      data.sort( (a,b) => b.id - a.id )
      data2 = 'descending'
    }

    this.setState({ 
      news: data,
      sortOrder: data2
    });
  }

  render() {
    const news = this.state.news

    return (
      <div>
        <div className="sort">
            <a
              href="#"
              className={"ascending"}
              onClick={this.sortOrder.bind(this, "ascending")}>
              Ascending
            </a>|
            <a
              href="#"
              className={"descending"}
              onClick={this.sortOrder.bind(this, "descending")}>
              Date
            </a>
          </div>


        {news && news.map(post =>
          <div key={post.id} className="news-item">
              <p>
                <span className="news-position">{post.id}. ▲</span> {post.title}{" "}
                <small>(by {post.author})</small>
              </p>
              <small className="news-details">
                {post.upvotes} upvotes
              </small>
          </div>
        )}
      </div>
    );
  }
}

提前感谢您的帮助

1 个答案:

答案 0 :(得分:0)

你的代码看起来很好。发生以下情况:

componentDidMount中,您需要初始数据。这是异步操作,意味着componentDidMount将在不等待它完成的情况下完成,并且console.log('2 ' + this.state)将被执行,之后将调用初始渲染而不存在任何数据。

然后requestInitialData完成,您会看到console.log('1 ' + data)已登录。之后,您更新状态(请注意,setState也是异步的),然后使用数据再次呈现新闻。

ui未被更新的原因可能是NewsList实现shouldComponentUpdate并且在某些条件下不会重新呈现。

我建议将记录放在NewsNewsList的渲染方法中,看看它们是如何被调用的。并且您确实从requestInitialData方法获取数据。