I have a Tensorflow model and I have converted it to ".tflite" but I don't know the way how to implement it on android. I followed the TensorFlow guidelines to implement it in android but since there is no XML code given the TensorFlow website I am struggling to connect it with the front end (XML). I need a clear explanation of how to use my model in android studio using java.
I followed the official instructions given in the TensorFlow website to implement the model in android.
A sample code of how to implement object detection based on tflite model from Tensorflow. I suppose these kinds of answers are not the best answers, but I happened to have a simple example of your exact problem.
Note: it does detect objects and outputs their labels into standard output using Log.d. No boxes or labels will be drawn around detected images.
Download started models and labels from here. Put them into the assets folder of your project.
Java
import android.content.pm.PackageManager;
import android.media.Image;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.common.model.LocalModel;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.objects.DetectedObject;
import com.google.mlkit.vision.objects.ObjectDetection;
import com.google.mlkit.vision.objects.ObjectDetector;
import com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.ExecutionException;
public class ActivityExample extends AppCompatActivity {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private ObjectDetector objectDetector;
private PreviewView prevView;
private List<String> labels;
private int REQUEST_CODE_PERMISSIONS = 101;
private String[] REQUIRED_PERMISSIONS =
new String[]{"android.permission.CAMERA"};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen);
prevView = findViewById(R.id.viewFinder);
prepareObjectDetector();
prepareLabels();
if (allPermissionsGranted()) {
startCamera();
} else {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
}
private void prepareLabels() {
try {
InputStreamReader reader = new InputStreamReader(getAssets().open("labels_mobilenet_quant_v1_224.txt"));
labels = readLines(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
private List<String> readLines(InputStreamReader reader) {
BufferedReader bufferedReader = new BufferedReader(reader, 8 * 1024);
Iterator<String> iterator = new LinesSequence(bufferedReader);
ArrayList<String> list = new ArrayList<>();
while (iterator.hasNext()) {
list.add(iterator.next());
}
return list;
}
private void prepareObjectDetector() {
CustomObjectDetectorOptions options = new CustomObjectDetectorOptions.Builder(loadModel("mobilenet_v1_1.0_224_quant.tflite"))
.setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE)
.enableMultipleObjects()
.enableClassification()
.setClassificationConfidenceThreshold(0.5f)
.setMaxPerObjectLabelCount(3)
.build();
objectDetector = ObjectDetection.getClient(options);
}
private LocalModel loadModel(String assetFileName) {
return new LocalModel.Builder()
.setAssetFilePath(assetFileName)
.build();
}
private void startCamera() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException e) {
// No errors need to be handled for this Future.
// This should never be reached.
} catch (InterruptedException e) {
}
}, ContextCompat.getMainExecutor(this));
}
private void bindPreview(ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder().build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
YourAnalyzer yourAnalyzer = new YourAnalyzer();
yourAnalyzer.setObjectDetector(objectDetector, labels);
imageAnalysis.setAnalyzer(
ContextCompat.getMainExecutor(this),
yourAnalyzer);
Camera camera =
cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageAnalysis
);
preview.setSurfaceProvider(prevView.createSurfaceProvider(camera.getCameraInfo()));
}
private Boolean allPermissionsGranted() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(
this,
permission
) != PackageManager.PERMISSION_GRANTED
) {
return false;
}
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera();
} else {
Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT)
.show();
finish();
}
}
}
private static class YourAnalyzer implements ImageAnalysis.Analyzer {
private ObjectDetector objectDetector;
private List<String> labels;
public void setObjectDetector(ObjectDetector objectDetector, List<String> labels) {
this.objectDetector = objectDetector;
this.labels = labels;
}
#Override
#ExperimentalGetImage
public void analyze(#NonNull ImageProxy imageProxy) {
Image mediaImage = imageProxy.getImage();
if (mediaImage != null) {
InputImage image = InputImage.fromMediaImage(
mediaImage,
imageProxy.getImageInfo().getRotationDegrees()
);
objectDetector
.process(image)
.addOnFailureListener(e -> imageProxy.close())
.addOnSuccessListener(detectedObjects -> {
// list of detectedObjects has all the information you need
StringBuilder builder = new StringBuilder();
for (DetectedObject detectedObject : detectedObjects) {
for (DetectedObject.Label label : detectedObject.getLabels()) {
builder.append(labels.get(label.getIndex()));
builder.append("\n");
}
}
Log.d("OBJECTS DETECTED", builder.toString().trim());
imageProxy.close();
});
}
}
}
static class LinesSequence implements Iterator<String> {
private BufferedReader reader;
private String nextValue;
private Boolean done = false;
public LinesSequence(BufferedReader reader) {
this.reader = reader;
}
#Override
public boolean hasNext() {
if (nextValue == null && !done) {
try {
nextValue = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
nextValue = null;
}
if (nextValue == null) done = true;
}
return nextValue != null;
}
#Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String answer = nextValue;
nextValue = null;
return answer;
}
}
}
XML layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.camera.view.PreviewView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/viewFinder"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Gradle file configuration
android {
...
aaptOptions {
noCompress "tflite" // Your model\'s file extension: "tflite", "lite", etc.
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
...
implementation 'com.google.mlkit:object-detection-custom:16.0.0'
def camerax_version = "1.0.0-beta03"
// CameraX core library using camera2 implementation
implementation "androidx.camera:camera-camera2:$camerax_version"
// CameraX Lifecycle Library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha10"
}
Related
I am writing a program that requires the starting of a python script before the rest of the java code runs. However, I cannot find a solution to my issues. I would appreciate if someone could suggest a solution to the problem I am facing.
Code (I need help on the part under the comment "start python"):
import java.io.IOException;
//makes it easier for user to
//select game/start python
public class gameselect {
public static void main(String args[]) throws IOException {
//start python
try {
String cmd = "python ngramcount.py";
Process process = Runtime.getRuntime().exec(cmd);
process.getInputStream();
}
catch (IOException e) {
e.printStackTrace();
}
//select game
try {
Scanner in = new Scanner (System.in);
game1 g = new game1();
game2 f = new game2();
int choice = 0;
System.out.println("Welcome to TranslateGame!");
System.out.println("Type 1 for game1 (words) or 2 for game2 (phrases)");
while (choice != 1 && choice != 2) {
choice = in.nextInt();
if (choice != 1 && choice != 2) {
System.out.println("No game associated with that number.");
}
}
if (choice == 1) {
g.game1();
}
else if (choice == 2) {
f.game2();
}
}
catch(IOException e) {
System.out.println("No.");
}
}
}
Here is some code that you might be able to get to work. I also commented it and provided some reference links to help you understand what the code is doing.
public static void main(String[] args) throws IOException {
// I'm using the absolute path for my example.
String fileName = "C:\\Users\\yourname\\Desktop\\testing.py";
// Creates a ProcessBuilder
// doc: https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html
ProcessBuilder pb = new ProcessBuilder("python", fileName);
pb.redirectErrorStream(true); // redirect error stream to a standard output stream
Process process = pb.start(); // Used to start the process
// Reads the output stream of the process.
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line; // this will be used to read the output line by line. Helpful in troubleshooting.
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
This is my definition dto class:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace DeserializeDemo
{
public class SubTaskRuleDto
{
public Guid Id { get; set; }
[JsonConverter(typeof(ByteArrayConverter))]
public byte[] Content { get; set; }
public bool DisableImage { get; set; }
public bool UseMobileAgent { get; set; }
public bool SupplementEnable { get; set; }
}
public class ByteArrayConverter : JsonConverter<byte[]>
{
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
short[] sByteArray = JsonSerializer.Deserialize<short[]>(ref reader);
byte[] value = new byte[sByteArray.Length];
for (int i = 0; i < sByteArray.Length; i++)
{
value[i] = (byte)sByteArray[i];
}
return value;
}
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
{
writer.WriteStartArray();
foreach (var val in value)
{
writer.WriteNumberValue(val);
}
writer.WriteEndArray();
}
}
}
Then I Will show the asp.net core Controller code:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
namespace DeserializeDemo.Controllers
{
[ApiController]
[Route("[controller]")]
public class Clouds : ControllerBase
{
private readonly ILogger<Clouds> _logger;
public Clouds(ILogger<Clouds> logger)
{
_logger = logger;
}
[HttpGet]
public SubTaskRuleDto Get()
{
return new SubTaskRuleDto()
{
Id = Guid.NewGuid(),
Content = new byte[] { 1, 7},
DisableImage = false,
UseMobileAgent = true,
SupplementEnable = false,
};
}
public enum ContentType
{
Xoml = 1,
Python = 7,
NodeJS = 8
}
}
}
The api works well, and test ok in postman:
enter image description here
When I call the api in my python client, my code just like this:
# -*- coding:utf-8 -*-
import json
import deserialize
import requests
class SubTaskRuleRes:
id: str
content: str
disableImage: bool
useMobileAgent: bool
supplementEnable: bool
def get_subtask_rule():
url = "http://localhost:5000/clouds"
res = requests.get(url)
# print(res.content)
# binary = res.content
# output = json.loads(binary)
my_instance = deserialize.deserialize(SubTaskRuleRes, res.json())
print(my_instance)
get_subtask_rule()
deserialize- 1.8.3 - https://github.com/dalemyers/deserialize
The problem is I Cannot deserialize a list to '<class 'str'>' or a list for SubTaskRuleRes.content.
deserialize does not perform implicit type conversion. That is the reason for the error you get (note, always post the full traceback you get).
Looking at the docs, you can use decorator to pass a parser function (look at Advanced Usage/Parsers, e.g.
import deserialize
#deserialize.parser("content", str)
class SubTaskRuleRes:
id: str
content: str
disableImage: bool
useMobileAgent: bool
supplementEnable: bool
def get_subtask_rule():
spam = {'id':'28631ee-abd', 'content':[1, 7],
'disableImage': False, 'useMobileAgent':True,
'supplementEnable': False}
return deserialize.deserialize(SubTaskRuleRes, spam)
rule = get_subtask_rule()
print(rule.content)
print(type(rule.content))
output
[1, 7]
<class 'str'>
Note, I am not sure why would you want content to be list literal, string
So I created my custom model for disease recognition based on the symptoms entered by the patient. And it works perfectly on python, However after I converted it to tflite and ran it on android studio, It gives me wrong predictions irrespective of the input values.
I've tested the tflite model on python and it's working fine.
Following code shows how I converted my model to tflite:-
from tensorflow.keras.models import load_model
saved_model= load_model('Disease-predictor_ANN.h5')
#Convert to tflite model
from tensorflow import lite
converter= lite.TFLiteConverter.from_keras_model(saved_model)
tflite_model= converter.convert()
#Save the model
with open('dpredictor.tflite','wb') as f:
f.write(tflite_model)
The following code shows my activity file where I have implemented the tflite model in android studio:-
package com.example.prototype_idoc;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.MultiAutoCompleteTextView;
import android.widget.TextView;
import android.widget.Toast;
import org.tensorflow.lite.DataType;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer;
import org.tensorflow.lite.support.tensorbuffer.TensorBufferFloat;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
public class diseaseDiagnosis extends AppCompatActivity {
private MultiAutoCompleteTextView multiAutoCompleteTextView;
private Button button;
private TextView textView;
public diseaseDiagnosis() throws PackageManager.NameNotFoundException {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_disease_diagnosis);
MapdatabaseHelper mapdatabaseHelper= new MapdatabaseHelper(this);
try {
mapdatabaseHelper.createDatabase();
mapdatabaseHelper.openDatabase();
} catch (IOException e) {
e.printStackTrace();
}
ArrayList<String> symptomList= (ArrayList<String>) mapdatabaseHelper.getEverySymptom(this);
ArrayList<String> diseaseList= (ArrayList<String>) mapdatabaseHelper.getEveryDisease(this);
String[] symptoms= symptomList.toArray(new String[symptomList.size()]);
String[] diseases= diseaseList.toArray(new String[diseaseList.size()]);
mapdatabaseHelper.close();
multiAutoCompleteTextView= findViewById(R.id.multiAutoView);
button= findViewById(R.id.checkDisease);
textView= findViewById(R.id.diseaseName);
ArrayAdapter<String> arrayAdapter= new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,symptoms);
multiAutoCompleteTextView.setAdapter(arrayAdapter);
multiAutoCompleteTextView.setThreshold(1);
multiAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
float[] model_input= new float[132];
Arrays.fill(model_input, new Float(0));
String itemsSelected= multiAutoCompleteTextView.getText().toString();
int startIndex=0;
for(int i=0;i<itemsSelected.length();i++){
if(itemsSelected.charAt(i)==','){
String s=itemsSelected.substring(startIndex,i);
int currIndex=symptomList.indexOf(s);
Log.v("CURR INDEX:",s+ ":"+currIndex);
model_input[currIndex]= 1.0F;
startIndex=i+2;
}
}
Context context = null;
try {
context = createPackageContext("com.example.prototype_idoc", 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
AssetManager assetManager = context.getAssets();
Interpreter interpreter=null;
try {
interpreter= new Interpreter(loadModelFile(assetManager,"dpredictor.tflite"));
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer inputBuffer=ByteBuffer.allocateDirect(132*4).order(ByteOrder.nativeOrder());
inputBuffer.rewind();
for(int i=0;i<model_input.length;i++){
inputBuffer.putFloat(model_input[i]);
}
float[] outputArray= new float[41];
TensorBuffer outputBuffer= TensorBuffer.createFixedSize(new int[]{1,41},DataType.FLOAT32);
interpreter.run(inputBuffer,outputBuffer.getBuffer());
outputArray= outputBuffer.getFloatArray();
//
int modelOutputIndex= 0;
float maxNum= outputArray[0];
for(int i=0;i<outputArray.length;i++){
if(maxNum>outputArray[i]){
modelOutputIndex=i;
maxNum=outputArray[i];
}
}
Log.v("TAG:", "onClick: "+ outputArray[15] );
Log.v("TAG:", "onClick: "+ outputArray[25] );
textView.setText(diseases[modelOutputIndex]);
textView.setVisibility(View.VISIBLE);
}
});
}
private MappedByteBuffer loadModelFile(AssetManager assetManager, String modelPath) throws IOException {
AssetFileDescriptor fileDescriptor = assetManager.openFd(modelPath);
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
FileChannel fileChannel = inputStream.getChannel();
long startOffset = fileDescriptor.getStartOffset();
long declaredLength = fileDescriptor.getDeclaredLength();
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}
I have multiple Hazelcast sets for which I want to find the Intersection, however I want to avoid pulling any data on the client side. My current approach is exactly that with this code. It finds intersection between the 1st set and the list of the rest of set so that set1 is now the intersection of all.
for i in range(1, len(sets)):
cur = sets[i]
set1.retain_all(cur.get_all())
Hazelcast's retain_all doesn't work with 2 set entities, only with a set and a collection which is not what I am looking for. For example, it can be done with Redis with this code, so I want its Hazelcast equivalent.
set_result = "set_result"
redisClient.sinterstore(set_result, *list(sets))
Any help would be appreciated!
Since Hazelcast's ISet is a Set which is a Collection the following code should work:
set1.retainAll(cur);
But, it doesn't seem like you'd like set1 to be modified but would rather store the result in a different set much like redis' sinterstore function.
The following is an example of an alternative implementation:
public class RetainAllExample {
public static void main(String[] args) {
HazelcastInstance h1 = Hazelcast.newHazelcastInstance();
HazelcastInstance h2 = Hazelcast.newHazelcastInstance();
Set<String> set1 = h1.getSet("set1");
Set<String> set2 = h1.getSet("set2");
set1.add("a");
set1.add("b");
set1.add("c");
set1.add("d");
set2.add("c");
set2.add("d");
set2.add("e");
String resultName = "result";
String[] setNames = new String[] { "set1", "set2"};
RetainAll retainAll = new RetainAll(resultName, setNames;
IExecutorService exec = h1.getExecutorService("HZ-Executor-1");
Future<Boolean> task = exec.submit(retainAll);
try {
if(task.get(1_000, TimeUnit.MILLISECONDS)) {
Set<String> result = h1.getSet(resultName);
result.forEach(str -> System.out.println(str + ", "));
}
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
System.exit(0);
}
static class RetainAll implements Callable<Boolean>, HazelcastInstanceAware, Serializable {
private HazelcastInstance hazelcastInstance;
private String resultSetName;
private String[] setNames;
public RetainAll(String resultSetName, String[] setNames) {
this.resultSetName = resultSetName;
this.setNames = setNames;
}
#Override
public Boolean call() {
try {
Set[] sets = new Set[setNames.length];
IntStream.range(0, setNames.length).forEach(i -> sets[i] = hazelcastInstance.getSet(setNames[i]));
ISet resultSet = hazelcastInstance.getSet(resultSetName);
resultSet.addAll(sets[0]);
IntStream.range(1, sets.length).forEach(i -> resultSet.retainAll(sets[i]));
}
catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
#Override
public void setHazelcastInstance(HazelcastInstance hazelcastInstance) {
this.hazelcastInstance = hazelcastInstance;
}
}
}
This question already has answers here:
Reactjs, Super expression must either be null or a function
(2 answers)
Closed 5 years ago.
So I'm new to React and even though I've found multiple others having the same issue, I still haven't found the error in my code. Therefore I turn to you stackoverflow, you're my only hope!
I am learning, so I wanted to create a simple ReactJS application that handles a HTTP-request. After finishing the code I encountered the error:
Uncaught TypeError: Super expression must either be null or a function, not object
at exports.default (inherits.js?0578:21)
at eval (app.js?71f7:22)
The error persists even though I've tried a lot of different changes and I am fairly certain that it's related to imports/exports as this is what a lot of other sources tell me, although double-checking imports etc. hasn't yielded any results.
The code:
app.js ( handles the rendering of a simple button and should execute a simple GET request on click )
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createServerSagaRequest } from '../saga/serverSaga'
import { incrRequestAmount, requestSelector } from '../reducer/requestReducer'
const mapStateToProps = (state) => {
return {
getRequestAmount: requestSelector.requests(state),
}
}
const mapDispatchToProps = (dispatch) => {
return {
open: (url, data, action, method) => dispatch(createServerSagaRequest((url, data, action, method))),
requests: () => dispatch(incrRequestAmount()),
}
}
class App extends React {
constructor(props){
super(props)
}
_buttonClick() {
this.props.requests()
this.props.open("http://mvctestproject.local/GetData", "TestDataFraGet", action, "GET")
}
render(){
return (
<button
className="btn btn-default"
onClick={this._buttonClick()}>{this.props.getRequestAmount()}
</button>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
serverSaga.js (my saga which can access the reducer and service)
import React, { Component } from 'react'
import { put, call, take, fork, select } from 'redux-saga/effects'
import { callServer } from '../service/serverService'
import { incrRequestAmount, requestSelector } from '../reducer/requestReducer'
export function createServerSagaRequest() {return { type: CREATE_REQUEST }}
function* handleRequest(url, data, action, method, success){
incrRequestAmount()
return yield executeRequest(url, data, action, method, success)
}
function* executeRequest(url, data, action, method, success) {
let response = yield call(callServer, url, method, data)
let responseSuccess = response && response.Succeeded
return
}
export default function* serverSaga(){
yield [
fork(function*(){
yield call (CREATE_REQUEST, handleRequest)
}),
]
}
rootSaga.js ( grouping sagas - in case I made more )
import { fork } from 'redux-saga/effects'
import serverSaga from './serverSaga'
export default function* rootSaga(){
yield [
fork(serverSaga)
]
}
requestReducer.js ( only function is to increment a variable after each request)
import { fromJS } from 'immutable'
export function incrRequestAmount() {return {type: 'INCR_REQUESTS'}}
const initialState = {
requestAmount: 0
}
function requestReducer(state = fromJS(initialState), action){
switch(action.type){
case 'INCR_REQUESTS':
return state.updateIn(["requestAmount"], (requests) => requests++)
default:
return state
}
}
export const requestSelector = {
amount: state => state.requests.get('requestAmount')
}
export default requestReducer
reducers.js ( grouping reducers - in case i made more )
import { combineReducers } from 'redux'
import React, { Component } from 'react'
import requests from './requestReducer'
export default combineReducers({
requests,
})
serverService.js ( handles calls to the server (GET/POST)
import React, { Component } from 'react'
export function callServer(url, bodyData, method){
let methodType = method.toLowerCase()
return new Promise((resolve, reject) => {
let r;
switch (methodType){
case 'post':
r = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(bodyData)
}
break;
case 'get':
r = {
method: 'GET'
}
break;
}
if (r) {
console.log("URL: ", url)
fetch(url, r)
.then((response) => {
console.log("Resp: ", url, response)
return response.json()
})
}
})
}
You need to extend React.Component to create a component, not React itself:
class App extends React {
should be
class App extends React.Component {
, or since you imported Component directly
class App extends Component {