diegohaz / arc

React starter kit based on Atomic Design
https://arc.js.org
2.91k stars 295 forks source link

[redux-ssr] Question about hasServerState, setServerState and cleanServerState #308

Open rolele opened 7 years ago

rolele commented 7 years ago

I have trouble understanding those 3 variables that are used for SSR. For example, I would like to understand that is the role of those variable for the container PostList.js

componentWillMount() {
    const { readList, hasServerState, setServerState, cleanServerState } = this.props

    if (!hasServerState) {
      if (isServer) {
        readList().then(setServerState, setServerState)
      } else {
        readList()
      }
    } else if (isBrowser) {
      cleanServerState()
    }
  }

...

const withServerState = fetchState(
  state => ({
    hasServerState: !!state.data,
  }),
  actions => ({
    setServerState: data => actions.done({ data }),
    cleanServerState: () => actions.done(),
  })
)

hasServerState: !!state.data, I am wondering when this conditional is true? I do not see the data property anywhere on the redux state. Where does state.data come from? Is it within the scope of the selector or is it the root state object?

setServerStatecall the done function with { data } where does this data go ? I guess this is not operating at the root level of the state, is it?

cleanServerState just call done. What is the purpose of this function ? Is there other use case where cleanServerState does a little more that that ?

Thanks for the good work. Cheers

diegohaz commented 7 years ago

You can have a look at https://github.com/gabrielbull/react-router-server to understand it better.

state in that case is the state passed from server to the client within react-router-server (here: https://github.com/diegohaz/arc/blob/redux-ssr/src-example/client.js#L16). That's not related to redux.

When I call actions.done({ data }), I'm setting state.data; when I call actions.done(), I'm cleaning state (it becomes {} by default).

Explaining the flow:

  componentWillMount() {
    const { readList, hasServerState, setServerState, cleanServerState } = this.props

    if (!hasServerState) {
      if (isServer) {
        // on server, it fetches data and sets server state so it can be sent to the client within react-router-server
        readList().then(setServerState, setServerState)
      } else {
        // this is the second time you open the page on the client
        readList()
      }
    } else if (isBrowser) {
      // this is the first time you open the page on the client. 
      // There's already data sent by the server, so it doesn't need to be fetched again. 
      // It just cleans server state so the second time you open that page will refresh data.
      cleanServerState()
    }
  }
rolele commented 7 years ago

Thanks for the answer it is a little bit clearer but because the example is using redux. Setting the routerServerState does not seams to do anything. On the PostList example window.__SERVER_STATE__ = {"1":{"data":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]}}; Which is basicaly never used because redux will only be interested in

window.__INITIAL_STATE__ = {"form":{"PostForm":{"syncErrors":{"title":"Required field","body":"Required field"},"registeredFields":{"title":{"name":"title","type":"Field","count":2},"body":{"name":"body","type":"Field","count":2}}}},"thunk":{"pending":{"postsListRead":false},"failure":{"postsListRead":false}},"entities":{"posts":{"1":{"userId":1,"id":1,"title":"sunt aut facere repellat provident occaecati excepturi optio reprehenderit","body":"quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"},"2":{"userId":1,"id":2,"title":"qui est esse","body":"est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"},"3":{"userId":1,"id":3,"title":"ea molestias quasi exercitationem repellat qui ipsa sit aut","body":"et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"},"4":{"userId":1,"id":4,"title":"eum et est occaecati","body":"ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"},"5":{"userId":1,"id":5,"title":"nesciunt quas odio","body":"repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"},"6":{"userId":1,"id":6,"title":"dolorem eum magni eos aperiam quia","body":"ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae"},"7":{"userId":1,"id":7,"title":"magnam facilis autem","body":"dolore placeat quibusdam ea quo vitae\nmagni quis enim qui quis quo nemo aut saepe\nquidem repellat excepturi ut quia\nsunt ut sequi eos ea sed quas"},"8":{"userId":1,"id":8,"title":"dolorem dolore est ipsam","body":"dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae"},"9":{"userId":1,"id":9,"title":"nesciunt iure omnis dolorem tempora et accusantium","body":"consectetur animi nesciunt iure dolore\nenim quia ad\nveniam autem ut quam aut nobis\net est aut quod aut provident voluptas autem voluptas"},"10":{"userId":1,"id":10,"title":"optio molestias id quia eum","body":"quo et expedita modi cum officia vel magni\ndoloribus qui repudiandae\nvero nisi sit\nquos veniam quod sed accusamus veritatis error"},"11":{"userId":2,"id":11,"title":"et ea vero quia laudantium autem","body":"delectus reiciendis molestiae occaecati non minima eveniet qui voluptatibus\naccusamus in eum beatae sit\nvel qui neque voluptates ut commodi qui incidunt\nut animi commodi"},"12":{"userId":2,"id":12,"title":"in quibusdam tempore odit est dolorem","body":"itaque id aut magnam\npraesentium quia et ea odit et ea voluptas et\nsapiente quia nihil amet occaecati quia id voluptatem\nincidunt ea est distinctio odio"},"13":{"userId":2,"id":13,"title":"dolorum ut in voluptas mollitia et saepe quo animi","body":"aut dicta possimus sint mollitia voluptas commodi quo doloremque\niste corrupti reiciendis voluptatem eius rerum\nsit cumque quod eligendi laborum minima\nperferendis recusandae assumenda consectetur porro architecto ipsum ipsam"},"14":{"userId":2,"id":14,"title":"voluptatem eligendi optio","body":"fuga et accusamus dolorum perferendis illo voluptas\nnon doloremque neque facere\nad qui dolorum molestiae beatae\nsed aut voluptas totam sit illum"},"15":{"userId":2,"id":15,"title":"eveniet quod temporibus","body":"reprehenderit quos placeat\nvelit minima officia dolores impedit repudiandae molestiae nam\nvoluptas recusandae quis delectus\nofficiis harum fugiat vitae"}}},"modal":{},"resource":{"posts":{"list":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],"detail":null}},"social":{"user":null}};

I think this <ServerStateProvider state={serverState}> Is only useful when you want the react router v4 to manage the state. Am I right?

rolele commented 7 years ago

maybe this react router server state should just contain flags saying: dataPostListLoaded: true so that when the client try to load the data hasServerState: !!state.dataPostListLoaded This way you could load more that 1 resource per page. Am I right?

diegohaz commented 7 years ago

Yeah, that works like a flag. [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] is what's returned from getList(). Thus, it's being passed to server state through setServerState.

For better clarity, maybe we should change the withServerState logic to use a flag, as you suggested. Would accept a PR. I'm not sure if it will break something though.

const withServerState = fetchState(
  state => ({
    hasServerState: !!state.postListLoaded,
  }),
  actions => ({
    setServerState: () => actions.done({ postListLoaded: true }),
    cleanServerState: () => actions.done({ postListLoaded: false }),
  })
)