Fetching data before rendering server side

断了今生、忘了曾经 提交于 2019-12-12 14:43:13

问题


Right now I'm discovering Este.js and I have a little issue with isomorphic apps. I don't understand how to make api call before rendering server side with renderToString().

One solution consists in doing all the data fetching at the router level using React Router. Depending on the top level route, I can predict which data will be needed, make the api call, and then call React.renderToString.

Great, but I still have to declare the data dependencies at the component level AND in the router level. I end up writing the same code twice, and I don't believe it's the best way to do it.

EDIT : Ok, for now I'm able to do somewhat what I want. Using React-Router and this link I've been able to made the following :

Giving this global app state, I want to prefetch todos when pointing /todos

initialstate.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
  }
}

todos.react.js

In todo component I declare a static function fetchData. Because I want to retrieve the correct key in my appState, I pass 'list' as a param. Feels dirty.

class Todos extends Component {

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

  componentDidMount(){
    Todos.fetchData();
  }

  render() {
    ...
  }

}

actions.js

Api call and stuff, I pass the key to the promise - Feels hacky

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);

}

render.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();

  });


});

As you can see, I'll create a function to update appState with the updated todoList.

Is this ok to do all of this ? I would like to have some feedback please, because I feel like I'm going in a dark path :(.


回答1:


I accomplished this in my isomorphic server side app by putting my fetchData functions in the statics object of the component(s) and using promises that wait until all the data is returned before rendering the app to string.

Then you would pass the returned data down to the rendered component via props. This example was instrumental in my development of this app. React Router Mega Demo.



来源:https://stackoverflow.com/questions/30974007/fetching-data-before-rendering-server-side

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!