Javascript-форум (https://javascript.ru/forum/)
-   Библиотеки/Тулкиты/Фреймворки (https://javascript.ru/forum/library-toolkit-framework/)
-   -   React, single page (https://javascript.ru/forum/library-toolkit-framework/75853-react-single-page.html)

Alexandroppolus 12.11.2018 15:09

React, single page
 
сабж делается из несинглпейджа (сейчас на каждую страницу свой питоновский шаблон, index.jsx с рендерингом и т.д. - рендеринг только клиентский, серверный не нужен)

По замыслу хочется один шаблон, в нем роутер. Для каждой страницы есть свои скрипты, свой рендеринг, и это все должно подгружаться при необходимости.

т.е. открыли страницу - покрутился спиннер, все загрузилось и нарисовалось. Жмякнули ссылку перехода - покрутился спиннер рядом со ссылкой, догрузилось что надо, перерисовалось. Жмякнули одну ссылку а потом сразу другую (не дождавшись первую), должна нарисоваться страница по второй. Вот примерно такие кейсы, если упрощенно.

какие тут бестпрактисы, как это всё красиво обстряпать?

Alexandroppolus 12.11.2018 15:09

по реакту большого опыта нет

SuperZen 13.11.2018 12:40

для React16.6 сделали lazy, читать тут - https://reactjs.org/blog/2018/10/23/react-v-16-6.html

раньше было так (есть другие аналоги): https://github.com/jamiebuilds/react-loadable

ну и обычный роутер https://github.com/ReactTraining/react-router

можно посмотреть React16.7 правда его еще в мастер не коммитили, там есть Hook'и, проще подключать мултипл-контекс,

про state management - надо сначала посмотреть context - https://reactjs.org/docs/context.html

делаешь классы в них хранишь данные, пишешь ф-ции, которые обрабатывают данные

если этого мало смотрим redux+saga, или mobx

итого: context + router + lazy

Alexandroppolus 13.11.2018 18:59

спасибо, глянул.
lazy не совсем то - там предполагается, что при нажатии на ссылку старая верстка исчезает и показывается только то что в свойстве fallback, пока грузятся компоненты для новой страницы. А мне надо во время загрузки не затирать то что есть, просто показывать лоадер где-то сверху

SuperZen 13.11.2018 20:42

задача very complex, ) если не знать куда жать...

вот тебе мини прожект:

.babelrc
{
  "presets": [
    "env",
    "react",
    "es2015",
    "stage-0"
  ],
  "plugins": [
    "transform-class-properties"
  ]
}


package.json
{
  "name": "ttttest",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "babel-core": "^6.26.3",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-env": "^1.7.0",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.24.1",
    "express": "^4.16.4",
    "parcel-bundler": "^1.10.3",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-router": "^4.3.1",
    "react-router-dom": "^4.3.1"
  }
}


server.js
const path = require('path')
const Bundler = require('parcel-bundler')
const bundler = new Bundler(path.join(__dirname, 'src', 'index.html'), {})
const express = require('express')
const app = express()
const server = require('http').Server(app)
// const io = require('socket.io')(server)

const server_messages = [
  { id: 1, title: 'message1' },
  { id: 2, title: 'message2' }
]

app.use(express.static(path.join(__dirname, 'public')))

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})

app.get('/data', function (req, res) {
  setTimeout(() => res.json(server_messages), 5000)
})

// io.on('connection', function (socket) {
// })

app.use(bundler.middleware())

server.listen(2999, () => console.log('started at http://localhost:2999'))


src/index.html
<html>

<head></head>

<body>
  <div id="app"></div>
  <script type="text/javascript" src="index.js"></script>
</body>

</html>


src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import createBrowserHistory from "history/createBrowserHistory";
import { Router, Route, Link } from "react-router-dom"

const browserHistory = createBrowserHistory()

class Index extends React.Component {
  state = {
    loading: false
  }
  render() {
    return <React.Fragment>
      <h2>Home</h2>
      <button onClick={() => {
        this.setState({ loading: true })
        fetch('/data').then(r => r.json()).then(data => this.setState({ data, loading: false }))
      }}>getData</button>
      <button onClick={() => console.log('cancel')}>cancel request</button>
      {this.state.loading && <div>loading...</div>}
      {this.state.data && this.state.data.map(d => <div>{`${d.id} - ${d.title}`}</div>)}
    </React.Fragment>
  }
}
const About = () => <h2>About</h2>
const Users = () => <h2>Users</h2>

ReactDOM.render(
  <Router history={browserHistory}>
    <div>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about/">About</Link>
          </li>
          <li>
            <Link to="/users/">Users</Link>
          </li>
        </ul>
      </nav>

      <Route path="/" exact component={Index} />
      <Route path="/about/" component={About} />
      <Route path="/users/" component={Users} />
    </div>
  </Router>,
  document.getElementById('app')
)


осталось сделать fetch cancelable:
https://developers.google.com/web/up...bortable-fetch
https://stackoverflow.com/questions/...-fetch-request

или использовать https://github.com/axios/axios
у него есть cancel

или забить на это и продумать поведение приложения заранее... )

j0hnik 18.11.2018 13:13

Alexandroppolus,
С поисковой оптимизацией все так же возникают проблемы.
На днях общался с очень уважаемым в SEO сфере человеком, он подтвердил.

SuperZen 19.11.2018 12:39

в 17 версии обещают server side rendering из коробки )


Часовой пояс GMT +3, время: 01:35.