在渲染服务器端之前获取数据

IT技术 javascript reactjs fetch react-router isomorphism
2021-05-22 07:59:29

现在我正在发现Este.js并且我对同构应用程序有一个小问题。我不明白如何在使用 renderToString() 渲染服务器端之前进行 api 调用。

一种解决方案是使用 React Router 在路由器级别进行所有数据获取。根据顶级路由,我可以预测需要哪些数据,进行 api 调用,然后调用 React.renderToString。

很好,但我仍然必须在组件级别和路由器级别声明数据依赖项。我最终编写了两次相同的代码,而且我认为这不是最好的方法。

编辑:好的,现在我可以做一些我想做的事情。使用 React-Router 和这个链接我已经能够做到以下几点:

给这个全局应用状态,我想在指向 /todos 时预取 todos

初始状态.js

{
  auth: {
    data: null,
    form: null
  },
  examples: {
    editable: {
      state: null,
      text: 'Some inline-editable text.'
    }
  },
  i18n: {
    formats: {},
    locales: initialLocale,
    messages: messages[initialLocale]
  },
  pendingActions: {},
  todos: {
    editables: {},
    newTodo: {
      title: ''
    },
    list: [{
      id: 1,
      title: 'first todo yipiyo'
    }]
  },
  users: {
    viewer: null
  }
}

待办事项.react.js

在 todo 组件中,我声明了一个静态函数 fetchData。因为我想在我的 appState 中检索正确的键,所以我将“list”作为参数传递。感觉很脏

class Todos extends Component {

  static fetchData(){
    return actions.loadAllTodos('list');
  }

  componentDidMount(){
    Todos.fetchData();
  }

  render() {
    ...
  }

}

动作.js

Api 调用和其他东西,我传递了Promise的关键 - 感觉很糟糕

export function loadAllTodos(key) {

  const promise = new Promise((resolve, reject) => {

    Api.get()
    .then(res => {
      res.key = key; //hacky time
      resolve(res)
    })
    .catch(err => {
      reject(err);
    })

  });

  return dispatch(loadAllTodos, promise);

}

渲染.js

router.run((Handler, routerState) => {

  var promise = Promise.all(routerState.routes
        .filter(route => route.handler.fetchData)
        .map(route => {
          return route.handler.fetchData();
        })
      );

  promise.then(resp => {

    console.log(resp);

    //Displays : 
    [ { id: 2, title: 'Im a second todo' },{ id: 3, title: 'I like todo' },
    cursor: 'list' ]

    //Some stuff to add resp to appState, using the correct key, yey iso+api=win
    appState = mergeThisWithMagic(appState, resp);

    const html = preloadAppStateThenRenderHtml(Handler, appState);
    const notFound = routerState.routes.some(route => route.name ===
      'not-found');
    const status = notFound ? 404 : 200;
    res.status(status).send(html);
    resolve();

  });


});

如您所见,我将创建一个函数来使用更新后的 todoList 更新 appState。

这样做可以吗?我想得到一些反馈,因为我觉得我正走在一条黑暗的道路上:(。

1个回答

我通过将我的 fetchData 函数放在statics组件对象中并使用在将应用程序呈现为字符串之前等待所有数据返回的Promise在我的同构服务器端应用程序中完成了这一点

然后你可以通过 props 将返回的数据传递给渲染的组件。这个例子对我开发这个应用程序很有帮助。react-router巨型演示