title: how use React Hooks to consume Spring WebFlux service
body: <p>I understand/believe I should favour Functional Components instead of Class Components in order to apply Responsibility Isolation. With advent of React Hooks it brings a new approach to avoid Class and still have the feature keep state.</p>
  
  <p>I create a very simple Web Flux rest service. I created a very simple React page using Hooks and Axon and I am getting "data.map is not a function at RestApiHooksComponent". If I try this exact same code consuming a typical rest service it will work properly (by typical rest service I mean a syncronous code without any reactive feature).</p>
  
  <p>I guess I am missing some basic idea when mathing React with Web Flux. There are few examples around showing how to consume Webflux by React but no one showing how using Hooks (at least I didn't find it). Isn't Hooks compliance with Reactive paradigma? Based on my React limited knowlodge I guess it is going to be a good match: common user case is consuming a list from service that come in stream and showing it as it is available. </p>
  
  <p>Front End</p>
  
  <p>package.json</p>
  
  <pre><code>...
    "dependencies": {
      "axios": "^0.18.0",
      "react": "^16.8.6",
      "react-dom": "^16.8.6",
      "react-scripts": "3.0.1"
    },
    "scripts": {
      "start": "react-scripts start",
      "build": "react-scripts build",
      "test": "react-scripts test",
      "eject": "react-scripts eject"
    }
  ...
  </code></pre>
  
  <p>App.js</p>
  
  <pre><code>import React, { useEffect, useState } from "react";
  import axios from "axios";
  
  export default function RestApiHooksComponent() {
    const [data, setData] = useState([]);
  
    useEffect(() =&gt; {
      axios
        .get("http://127.0.0.1:8080")
        .then(result =&gt; setData(result.data));
    }, []);
  
    return (
      &lt;div&gt;
        &lt;ul&gt;
          {data.map(item =&gt; (
            &lt;li key={item.result}&gt;
              {item.result}: {item.result}
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;
    );
  }
  </code></pre>
  
  <p>index.js</p>
  
  <pre><code>import React from 'react';
  import ReactDOM from 'react-dom';
  import './index.css';
  import App from './App';
  
  
  ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));
  </code></pre>
  
  <p>LoanTable.js</p>
  
  <pre><code>import React from 'react'
  
  const LoanTable = props =&gt; (
      &lt;table&gt;
          &lt;thead&gt;
              &lt;tr&gt;
                  &lt;th&gt;Result&lt;/th&gt;
              &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
              {props.loans.length &gt; 0 ? (
                  props.loans.map(loan =&gt; (
                      &lt;tr&gt;
                          &lt;td&gt;{loan.result}&lt;/td&gt;
  
                      &lt;/tr&gt;
                  ))
              ) : (
                      &lt;tr&gt;
                          &lt;td&gt;No loans&lt;/td&gt;
                      &lt;/tr&gt;
                  )}
          &lt;/tbody&gt;
      &lt;/table&gt;
  )
  
  export default LoanTable
  </code></pre>
  
  <p>Webflux Rest Service</p>
  
  <p>Controller:</p>
  
  <pre><code>@RestController
  public class LoansController {
      @Autowired
      private LoansService loansService;
  
      @CrossOrigin
      @RequestMapping(method = RequestMethod.GET, produces = MediaType.TEXT_EVENT_STREAM_VALUE)
      @ResponseBody
      public Flux&lt;Loans&gt; findAll() {
          Flux&lt;Loans&gt; loans = loansService.findAll();
          return loans;
      }
  }
  </code></pre>
  
  <p>Service:</p>
  
  <pre><code>@Service
  public class LoansService implements ILoansService {
  
      @Autowired
      private LoansRepository loansRepository;
      @Override
      public Flux&lt;Loans&gt; findAll() {
  
          return loansRepository.findAll();
      }
  }
  </code></pre>
  
  <p>Webflux config</p>
  
  <pre><code>@Configuration
  @EnableWebFlux
  public class WebFluxConfig implements WebFluxConfigurer
  {  
  }
  </code></pre>
  
  <p>NOT MUCH RELEVANT DETAILS BUT I ADDED TO SHOW IT IS COMPLETELY NOBLOCKING CODE:</p>
  
  <p>MongoDb config</p>
  
  <pre><code>@Configuration
  @EnableReactiveMongoRepositories(basePackages = "com.mybank.web.repository")
  public class MongoConfig extends AbstractReactiveMongoConfiguration
  {  
      @Value("${port}")
      private String port;
  
      @Value("${dbname}")
      private String dbName;
  
      @Override
      public MongoClient reactiveMongoClient() {
          return MongoClients.create();
      }
  
      @Override
      protected String getDatabaseName() {
          return dbName;
      }
  
      @Bean
      public ReactiveMongoTemplate reactiveMongoTemplate() {
          return new ReactiveMongoTemplate(reactiveMongoClient(), getDatabaseName());
      }
  }
  </code></pre>
  
  <p>Pom:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
      &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
      &lt;parent&gt;
          &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
          &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
          &lt;version&gt;2.1.4.RELEASE&lt;/version&gt;
          &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
      &lt;/parent&gt;
      &lt;groupId&gt;com.mybank&lt;/groupId&gt;
      &lt;artifactId&gt;web&lt;/artifactId&gt;
      &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
      &lt;name&gt;web&lt;/name&gt;
      &lt;description&gt;webflux&lt;/description&gt;
  
      &lt;properties&gt;
          &lt;java.version&gt;11&lt;/java.version&gt;
      &lt;/properties&gt;
  
      &lt;dependencies&gt;
          &lt;dependency&gt;
              &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
              &lt;artifactId&gt;lombok&lt;/artifactId&gt;
              &lt;optional&gt;true&lt;/optional&gt;
          &lt;/dependency&gt;
          &lt;dependency&gt;
              &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
              &lt;artifactId&gt;spring-boot-starter-data-mongodb-reactive&lt;/artifactId&gt;
          &lt;/dependency&gt;
          &lt;dependency&gt;
              &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
              &lt;artifactId&gt;spring-boot-starter-webflux&lt;/artifactId&gt;
          &lt;/dependency&gt;
  
          &lt;dependency&gt;
              &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
              &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
              &lt;scope&gt;test&lt;/scope&gt;
          &lt;/dependency&gt;
          &lt;dependency&gt;
              &lt;groupId&gt;io.projectreactor&lt;/groupId&gt;
              &lt;artifactId&gt;reactor-test&lt;/artifactId&gt;
              &lt;scope&gt;test&lt;/scope&gt;
          &lt;/dependency&gt;
      &lt;/dependencies&gt;
  
      &lt;build&gt;
          &lt;plugins&gt;
              &lt;plugin&gt;
                  &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                  &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
              &lt;/plugin&gt;
          &lt;/plugins&gt;
      &lt;/build&gt;
  
  &lt;/project&gt;
  </code></pre>
  
  <p>*** edited</p>
  
  <p>web flux service output</p>
  
  <pre><code>data:{"timestamp":1558126555269,"result":"8"} data:{"timestamp":1558132444247,"result":"10"} data:{"timestamp":1558132477916,"result":"10"} data:{"timestamp":1558132596327,"result":"14"}
  </code></pre>