I learn React Javascript and Redux and now I have this problem.
Here's a codesandbox
Try like this:
- Search for book title "dep"
- Watch the log show "Search url is:", when it should show "Starting books search.."
I send two Redux dispatch after each other and the first never gets trough.
Basically it looks like this:
I have a Book Search app for learning React and in the app when press search for a book a dispatch is sent
This is the class sending the state:
import { booksActionTypes } from "./books.types";
export const showLog = () => ({
type: booksActionTypes.SHOWLOG,
});
export const setLogMessage = (log) => ({
type: booksActionTypes.LOG_MESSAGE,
payload: log,
});
export const clearPosts = () => ({
type: booksActionTypes.CLEAR_POSTS,
});
export const requestStart = () => ({
type: booksActionTypes.REQUEST_START,
});
export const requestSuccess = (booksList) => ({
type: booksActionTypes.REQUEST_SUCCESS,
payload: booksList,
});
export const requestFailure = (errMsg) => ({
type: booksActionTypes.REQUEST_FAILURE,
payload: errMsg,
});
export const actionCreators = {
// "applicationUrl": "http://localhost:51374", http://erikswed.ddns.net:8965/api/BooksXml/getbooks/fromall/?title=dep&author=&genre=&price=
// "sslPort": 44378
requestBooks: (book) => async (dispatch, getState) => {
dispatch(requestStart());
dispatch(
setLogMessage(() => ({
message: "Starting books search..",
timestamp:
new Date().getHours() +
"-" +
new Date().getMinutes() +
"-" +
new Date().getSeconds(),
type: "connecting",
}))
);
var queryString = Object.keys(book)
.map((key) => {
return encodeURIComponent(key) + "=" + encodeURIComponent(book[key]);
})
.join("&");
var url =
"htftp://erikswed.ddns.net:8965/api/BooksXml/getbooks/fromall/?" +
queryString;
dispatch(
setLogMessage(() => ({
message: "Search url is: ",
timestamp:
new Date().getHours() +
"-" +
new Date().getMinutes() +
"-" +
new Date().getSeconds(),
type: "connecting",
}))
);
dispatch(
setLogMessage(() => ({
message: "Sdsadsasada: ",
timestamp:
new Date().getHours() +
"-" +
new Date().getMinutes() +
"-" +
new Date().getSeconds(),
type: "connecting",
}))
);
await fetch(url)
.then((res) => res.json())
.then((xml) => {
dispatch(requestSuccess(xml));
})
.catch((errMsg) => {
console.log(errMsg);
dispatch(requestFailure(errMsg));
fetch("books.xml")
.then((res) => res.text())
.then((xmlString) => getFromLocalDatabas(dispatch, xmlString, book))
.catch((err) => {
dispatch(requestFailure(errMsg));
});
});
},
};
function getFromLocalDatabas(dispatch, xmlFile, book) {
var parser = new window.DOMParser();
var xmlDoc = parser.parseFromString(xmlFile, "text/xml");
var books = xmlDoc.documentElement.childNodes;
var map = [];
for (var i = 0; i < books.length; i++) {
var author = books[i]
.getElementsByTagName("author")[0]
.childNodes[0].nodeValue.toLowerCase();
var title = books[i]
.getElementsByTagName("title")[0]
.childNodes[0].nodeValue.toLowerCase();
var genre = books[i]
.getElementsByTagName("genre")[0]
.childNodes[0].nodeValue.toLowerCase();
var price = books[i]
.getElementsByTagName("price")[0]
.childNodes[0].nodeValue.toLowerCase();
var publish_date = books[i]
.getElementsByTagName("publish_date")[0]
.childNodes[0].nodeValue.toLowerCase();
var description = books[i]
.getElementsByTagName("description")[0]
.childNodes[0].nodeValue.toLowerCase();
if (book.author && author.indexOf(book.author.toLowerCase()) >= 0) {
sendBackThisBook(map, books[i]);
}
if (book.title && title.indexOf(book.title.toLowerCase()) >= 0) {
sendBackThisBook(map, books[i]);
}
if (book.genre && genre.indexOf(book.genre.toLowerCase()) >= 0) {
sendBackThisBook(map, books[i]);
}
if (book.price && price.indexOf(book.price.toLowerCase()) >= 0) {
sendBackThisBook(map, books[i]);
}
if (
book.publish_date &&
publish_date.indexOf(book.publish_date.toLowerCase()) >= 0
) {
sendBackThisBook(map, books[i]);
}
if (
book.description &&
description.indexOf(book.description.toLowerCase()) >= 0
) {
sendBackThisBook(map, books[i]);
}
}
dispatch(requestSuccess(map));
}
function sendBackThisBook(map, book) {
var index = map.findIndex((x) => x.id == book.getAttribute("id"));
if (index != -1) {
console.log(`exist skipping `, book.getAttribute("id"));
return;
}
map.push({
id: book.getAttribute("id"),
title: book.getElementsByTagName("title")[0].childNodes[0].nodeValue,
author: book.getElementsByTagName("author")[0].childNodes[0].nodeValue,
genre: book.getElementsByTagName("genre")[0].childNodes[0].nodeValue,
price: book.getElementsByTagName("price")[0].childNodes[0].nodeValue,
publish_date: book.getElementsByTagName("publish_date")[0].childNodes[0]
.nodeValue,
description: book.getElementsByTagName("description")[0].childNodes[0]
.nodeValue,
});
}
This is the Class receiving the Redux Store state:
import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { connect } from "react-redux";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableRow from "@material-ui/core/TableRow";
import { Icon } from "@material-ui/core";
import {
CallMade,
CallReceived,
FiberManualRecord,
Error,
} from "@material-ui/icons";
function createData(message, timestamp, type) {
return { message, timestamp, type };
}
const rows = [];
const useStyles = makeStyles((theme) => ({
root: {
width: "100%",
},
icons: {
fontSize: 18,
},
connecting: {
color: "#11FF0C",
},
connected: {
color: "#11FF0C",
},
disconnecting: {
color: "#FF5050",
},
disconnected: {
color: "#FF5050",
},
error: {
color: "#FF5050",
},
request: {
// color: "#11FF0C"
},
response: {
// color: "#11FF0C"
},
}));
function Logger(props) {
const { v4: uuidv4 } = require("uuid");
const classes = useStyles();
const [theLog, addLog] = useState([]);
useEffect(() => {
if (typeof props.log === "function") {
const values = props.log();
addLog([
...theLog,
createData(values.message, values.timestamp, values.type),
]);
}
}, [props.log]);
function createData(message, timestamp, type) {
console.log("s");
return { message, timestamp, type };
}
return (
<div>
{props.showLog ? (
<div className={classes.root}>
<Table aria-labelledby="tableTitle" size="small">
<TableBody>
{theLog.map((row, index) => {
return (
<TableRow
key={uuidv4()}
hover
role="checkbox"
tabIndex={-1}
key={row.timestamp}
>
<TableCell padding="checkbox">
<Icon>
{row.type === "connecting" && (
<FiberManualRecord
className={`${classes.connecting} ${classes.icons}`}
/>
)}
{row.type === "connected" && (
<FiberManualRecord
className={`${classes.connected} ${classes.icons}`}
/>
)}
{row.type === "disconnecting" && (
<FiberManualRecord
className={`${classes.disconnecting} ${classes.icons}`}
/>
)}
{row.type === "disconnected" && (
<FiberManualRecord
className={`${classes.disconnected} ${classes.icons}`}
/>
)}
{row.type === "error" && (
<Error
className={`${classes.error} ${classes.icons}`}
/>
)}
{row.type === "request" && (
<CallMade
className={`${classes.request} ${classes.icons}`}
/>
)}
{row.type === "response" && (
<CallReceived
className={`${classes.response} ${classes.icons}`}
/>
)}
</Icon>
</TableCell>
<TableCell>{row.message}</TableCell>
<TableCell>{row.timestamp}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
) : null}
</div>
);
}
function mapStateToProps(state) {
return {
log: state.reducer.log,
showLog: state.reducer.showLog,
};
}
export default connect(mapStateToProps, null)(Logger);
