import React from 'react' import { render } from 'react-dom' import { renderToString } from 'react-dom/server' import thunk from 'redux-thunk' import { Provider } from 'react-redux' import { createStore, applyMiddleware } from 'redux' import testmiddleware from './middlewares/testmiddleware' import promise from 'redux-promise' import reduxReset from 'redux-reset' import reducers from './reducers/reducers' import App from './components/app/app' const MIDDLEWARES = [ thunk, promise, testmiddleware ]; if (typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function') { window.renderClient = (state) => { let store = applyMiddleware(...MIDDLEWARES)(createStore)(reducers, state, reduxReset()); store.subscribe(() => console.log(store.getState())); render ( <Provider store={ store }> <App /> </Provider>, document.getElementById ('root') ); } } else { global.renderServer = (state) => { let store = applyMiddleware(...MIDDLEWARES)(createStore)(reducers, state, reduxReset()); store.subscribe(() => console.log(store.getState())); return renderToString ( <Provider store={ store }> <App /> </Provider> ) } }
import React from 'react' import AppTitle from 'arui-feather/app-title' import AppContent from 'arui-feather/app-content' import AuthForm from '../authform/authform' import Footer from 'arui-feather/footer' import Header from 'arui-feather/header' import Heading from 'arui-feather/heading' import Page from 'arui-feather/page' class App extends React.Component { render() { return ( <Page header={ <Header />} footer={<Footer />} > <AppTitle> <Heading> </Heading> </AppTitle> <AppContent> <AuthForm/> </AppContent> </Page> ); } } export default App;
import React from 'react' import { bindActionCreators } from 'redux' import {Field, formValueSelector, reduxForm } from 'redux-form' import { connect } from 'react-redux' import { makeTestAction } from '../../actions/testaction' import Button from 'arui-feather/button' import Form from 'arui-feather/form' import FormField from 'arui-feather/form-field' import Input from 'arui-feather/input' import Label from 'arui-feather/label' import { inputField } from '../../utils/componentFactory' let formConfig = { form: 'testForm' }; let foundStatus = ""; const selector = formValueSelector('testForm'); function mapStateToProps(state) { return { phoneField: selector(state, 'phoneNumber'), statusResp: state.testRed.respResult, answer: state.testRed.answerReceived }; } function mapDispatchToProps(dispatch) { return bindActionCreators( { makeTestAction }, dispatch ) } @reduxForm(formConfig) @connect(mapStateToProps, mapDispatchToProps) class AuthForm extends React.Component { render() { return ( <div> <Form noValidate={ true } onSubmit={ this.props.makeTestAction }> <FormField key='phoneNumber'> <Field name='phoneNumber' placeholder=' 79001234567' component={ inputField } size='m' /> </FormField> <FormField view='line'> <Button width='available' view='extra' size='m' type='submit'> </Button> </FormField> { this.renderFinalResult() } </Form> </div> ); } renderFinalResult() { foundStatus = this.props.statusResp; return (this.props.answer === true ) && <div> <FormField view='line' width='400px' label={ <Label size='m'> </Label> }> <Input size='m' width='available' value={ foundStatus } /> </FormField> </div> } } export default AuthForm;
import { TEST_ACTION, TEST_START, TEST_SUCCESS, TEST_FAILRULE } from '../constants/actions'; export function makeTestAction() { return { type: TEST_ACTION, actions: [ TEST_START, TEST_SUCCESS, TEST_FAILRULE ] } }
import { TEST_ACTION } from '../constants/actions' import superagent from 'superagent' const testmiddleware = store => next => action => { if (action.type !== TEST_ACTION) { return next(action); } const [ startAction, successAction, failureAction] = action.actions; const fieldName = action.fieldName; let state = store.getState(); let dataFetch = state.form.testForm.values; if (!action.value) { store.dispatch({ type: successAction, fieldName, payload:[] }); } store.dispatch({ type: startAction, fieldName }); superagent .get('/testep') .set('Content-Type', 'text/html; charset=utf-8') .query(dataFetch) .timeout(10000) .end((error, res) => { if (!error && res.ok) { store.dispatch({ type: successAction, fieldName, payload: JSON.parse(res.text) }); } else { console.log("ERROR!!!"); } }); return 1; }; export default testmiddleware;
import { TEST_SUCCESS } from '../constants/actions' let initialState = {}; export default function testReducer(state = initialState, action) { if (action.type === TEST_SUCCESS) { return { ...state, respResult: action.payload.name, answerReceived: true }; } return { ...state, answerReceived: false } }
package ru.alfabank.ef.configurations; import jdk.nashorn.api.scripting.NashornScriptEngine; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.stereotype.Component; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.io.IOException; @Component public class React { @Value(value = "classpath:static/nashorn-polyfill.js") private Resource nashornPolyfillFile; @Value(value = "classpath:static/bundle.js") private Resource bundleJsFile; public String renderEntryPoint() throws ScriptException, IOException { NashornScriptEngine nashornScriptEngine = getNashornScriptEngine(); try { Object html = nashornScriptEngine.invokeFunction("renderServer"); return String.valueOf(html); } catch (Exception e) { throw new IllegalStateException("Error! Failed to render react component!", e); } } private NashornScriptEngine getNashornScriptEngine() throws ScriptException, IOException { NashornScriptEngine nashornScriptEngine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName ("nashorn"); nashornScriptEngine.eval ("load ('" + nashornPolyfillFile.getFile().getCanonicalPath() + "')"); nashornScriptEngine.eval ("load ('" + bundleJsFile.getFile().getCanonicalPath() + "')"); return nashornScriptEngine; } }
package ru.alfabank.ef.controllers; import com.fasterxml.jackson.core.JsonProcessingException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import ru.alfabank.ef.configurations.React; import javax.script.ScriptException; import java.io.FileNotFoundException; @Controller public class MainController { private final React react; @Autowired public MainController(React react) { this.react = react; } @RequestMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE) public String mainPage(Model model) throws JsonProcessingException, ScriptException, FileNotFoundException { String renderedHTML = react.renderEntryPoint(); model.addAttribute("content", renderedHTML); return "index"; } }
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>SpringBoot & React | Progressive Webapp Demo</title> <link rel="stylesheet" href="/styles.css" /> </head> <body> <div id="root" th:utext="${content}"></div> <script src="/bundle.js"></script> <script th:inline="javascript"> window.renderClient(); </script> </body> </html>
Source: https://habr.com/ru/post/340776/
All Articles