SolidJS: "Unrecognized value" - javascript

I am able to receive the JSON value from the API path just fine.
Flask Code
app = Flask(__name__)
CORS(app)
#app.route("/cats-matches", methods=['POST'])
def cats_matches():
person = {"name": "John"} #Does not work
#person = [{"name": "John"}] #This works
return person
if __name__ == "__main__":
app.run(host="0.0.0.0",debug=True)
SolidJS
The "Go" button sets the web_orders signal to an object with the name data
That triggers the cats_matches resource to run fetchCatsMatches()
I call {cats_matches()} on the page just to dump the data
This shows correctly "[Object object]" if I return a List from the Flask route
Returning a Dict from Flask shows nothing on the page and has the console error: Unrecognized value. Skipped inserting {name: 'John'}
import { createSignal, createResource } from "solid-js";
const fetchCatsMatches = async (web_orders) =>
(await fetch('http://127.0.0.1:5000/cats-matches', {
method: "POST",
body: JSON.stringify(web_orders),
headers:{
"Content-type": "application/json; charset=UTF-8",
"Accept": "application/json"
}
})).json();
const CatsCustomerMatches = () => {
const [web_orders, setWebOrders] = createSignal([]);
const [cats_matches, { mutate, refetch }] = createResource(web_orders, fetchCatsMatches);
const getCatsMatches = () => {
setWebOrders([{'po': 123}]);
};
return (
<>
<button onClick={() => getCatsMatches()} >Go</button>
<p>{cats_matches()}</p>
</>
);
}
function App() {
return (
<div class="grid grid-cols-1">
<CatsCustomerMatches />
</div>
);
}
export default App;

That is because you are using an object directly in your rendering logic and jsx can not render objects directly. So, rather than outputting the resource, try stringifying it, so that you can avoid rendering errors:
<p>{JSON.stringify(cats_matches()}</p>
Solid somehow is more permissive with using array values directly than using object values. Either way you have error, [Object object] does not mean you are printing the value. In the case of an array, the value somehow gets converted into a string when the DOM element getting created and you see [Object object].
You can observe this easily:
import { render } from 'solid-js/web';
const App = () => {
const getValue = () => {
return {"name": "John"};
}
return (
<>
<p>{getValue()}</p>
</>
);
}
render(App, document.body);
You will get:
Unrecognized value. Skipped inserting
Object {name: "John"}
Try wrapping the value in an array, you will see the error is gone and the paragraph content becomes [Object object].
As a side note, you can wrap your application in an error boundary to get bettor error results:
const fallback = (err) => {
console.log(err);
return err.message;
}
<ErrorBoundary fallback={fallback}>
<App>{/* App content */}</App>
<ErrorBoundary

I tested the code, I observed that you can set initial value
const [cats_matches, { mutate, refetch }] = createResource(web_orders, fetchCatsMatches, { initialValue: { name: "" } });
Now change your display code as below
<>
<button onClick={() => getCatsMatches()} >Go</button>
<p>{cats_matches().name}</p>
</>
Or you can also use Suspense from these Examples Example1, Example2, Example3

Related

React query infinite scroll pageParams is undefined

I am trying to get data Using useInfiniteQuery, but on my console, I am getting the data but the pageParams is showing undefined, am I missing something to get the pageParams?
Here is my query hook
const useActivityFeedData = () => {
const {data} = useInfiniteQuery(
ACTIVITY_FEED,
({pageParam}) => Api.user.getActivityFeedData(pageParam),
{
getNextPageParam: (lastPage: any) => lastPage?.meta,
},
);
console.log(data)
};
My API
getActivityFeedData: (pageParam: number) => {
console.log(pageParam, 'pageParam'); // undefined
return api.get(
`/rest/s1/eyon/viewer/channel/activity-feed?pageSize=10&pageIndex=0`,
{},
{},
);
},
You're not missing anything - this is the intended behaviour. pageParams is always calculated for the next page, usually from the previous result. That's what you do in getNextPageParams.
For the first page, there is no "previous result", because it is the first page. That's why the pageParams are undefined. Note how we use default values during destructuring in the examples, e.g.:
const queryResult = useInfiniteQuery(
['projects'],
({ pageParam = 0 }) => axios.get('/api/projects?cursor=' + pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
}
)
for the first page, the cursor will be set to 0, as pageParam is undefined.
So it's just up to you to convert undefined to something that represents "the first page" for your api call.

How to create pages from non-seriazable data(functions)

I have this JavaScript data file(src/test/test.js):
module.exports = {
"title": "...",
"Number": "number1",
"Number2": ({ number1 }) => number1 / 2,
}
I want to pass this file verbatim(functions preserved) to a page, so that the page can use that data to build itself. I already have the page template and everything else sorted out, I just need to find a way to pass this into the page.
The first approach I tried is requireing this file in gatsby-node.js and then passing it as pageContext.
gatsby-node.js
const path = require('path');
exports.createPages = ({actions, graphql}) => {
const { createPage } = actions;
return graphql(`
query loadQuery {
allFile(filter: {sourceInstanceName: {eq: "test"}}) {
edges {
node {
relativePath
absolutePath
}
}
}
}
`).then(result => {
if (result.errors) {
throw result.errors;
}
for (const node of result.data.allFile.edges.map(e => e.node)) {
const data = require(node.absolutePath);
createPage({
path: node.relativePath,
component: path.resolve('./src/templates/test.js'),
context: data,
});
}
});
};
gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `test`,
path: `${__dirname}/src/test/`,
},
},
],
}
src/templates/test.js
import React from 'react';
const index = ({ pageContext }) => (
<p>{pageContext.Number2()}</p>
);
export default index;
However, I get this warning when running the dev server:
warn Error persisting state: ({ number1 }) => number1 / 2 could not be cloned.
If I ignore it and try to use the function anyway, Gatsby crashes with this error:
WebpackError: TypeError: pageContext.Number2 is not a function
After searching for a while, I found this:
The pageContext was always serialized so it never worked to pass a function and hence this isn't a bug. We might have not failed before though.
- Gatsby#23675
which told me this approach wouldn't work.
How could I pass this data into a page? I've considered JSON instead, however, JSON can't contain functions.
I've also tried finding a way to register a JSX object directly, however I couldn't find a way.
Regarding the main topic, as you spotted, can't be done that way because the data is serialized.
How could I pass this data into a page? I've considered JSON instead,
however, JSON can't contain functions.
Well, this is partially true. You can always do something like:
{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}
And then:
let func = new Function(function.arguments, function.body);
In this case, you are (de)serializing a JSON function, creating and casting a function based on JSON parameters. This approach may work in your scenario.
Regarding the JSX, I guess you can try something like:
for (const node of result.data.allFile.edges.map(e => e.node)) {
const data = require(node.absolutePath);
createPage({
path: node.relativePath,
component: path.resolve('./src/templates/test.js'),
context:{
someComponent: () => <h1>Hi!</h1>
},
});
}
And then:
import React from 'react';
const Index = ({ pageContext: { someComponent: SomeComponent} }) => (
return <div><SomeComponent /></div>
);
export default index;
Note: I don't know if it's a typo from the question but index should be capitalized as Index
In this case, you are aliasing the someComponent as SomeComponent, which is a valid React component.

API is returning data, but cannot read properties

Hello (I am learning React), I am working with an API that returns pictures of random people, however the problem I am having is when I use axios.get I am getting the response from the API, and I can see the results in the console, but when I try to access them it says "Cannot read properties of picture".
The thing I am making is that when the user press the input field it gets an URL of a random picture from the API and the value from that inputText changes to the URL, but it says "Cannot read properties of picture" when clicking on the input, but the API is returning me the data in the console.
Here is what my API returns me.
Here is my code.
class PersonasInsert extends Component {
urlPersonas = "https://randomuser.me/api/?inc=picture";
constructor(props) {
super(props);
this.state = {
peticionImagen: null,
name: "",
last: "",
image: "",
};
}
peticionImagenPersona = async () => {
await axios.get(this.urlPersonas).then(
(response) => {
this.setState({ peticionImagen: response.data.results });
},
(error) => {
console.log(error);
}
);
};
handleChangeImage = async (event) => {
this.peticionImagenPersona();
const peticionImagen = this.state.peticionImagen.picture.large
this.setState({ peticionImagen });
};
render() {
const { peticionImagen } = this.state;
return (
<Wrapper>
<Title>Insertar Persona</Title>
<Label>image: </Label>
<InputText
type="text"
value={peticionImagen}
readOnly
onClick={this.handleChangeImage}
/>
</Wrapper>
);
}
}
export default PersonasInsert;
Thank you in advance.
Does the API return an array of objects or a single object? It looks like an array from the log you posted, you will need to traverse the array through .map or if you want only the first element then do something like this: this.state.peticionImagen[0].picture.large

How can I resolve a TypeError where the property of length is undefined, when I have brackets set up to take in a string?

I am building my first react application and following a video from the page JavaScript Mastery (https://www.youtube.com/watch?v=khJlrj3Y6Ls). This project teaches me how to build a chart in react using data from an API to display global Covid-19 data. I tried to put the data into an empty array and loop through it using 'dailyData.length' but I keep getting a TypeError with length being undefined.
Here is my Chart.jsx
Import React, {useState, useEffect } from 'react';
import { fetchDailyData } from '../../api';
import { Line,Bar} from 'react-chartjs-2';
import styles from './Chart.module.css';
const Chart = () => {
const[dailyData, setDailyData] = useState([]); //here is where I set up the empty array.
useEffect(()=> {
const fetchAPI = async() => {
setDailyData (await fetchDailyData());
}
console.log(dailyData);
fetchAPI();
});
const lineChart = (
dailyData.length //this is where I am getting the error
? (
<Line
data={{
labels: dailyData.map(({ date }) => date),
datasets: [{
data: dailyData.map(({ confirmed }) => confirmed),
label:'Infected',
borderColor: '#3333ff',
fill: true,
}, {
data: dailyData.map(({ deaths }) => deaths),
label:'deaths',
borderColor: 'red',
backgroundColor: 'rgba(255, 0, 0, 0.5)',
fill: true,
}],
}}
/>) : null
My Index.js is the following:
import axios from 'axios';
const url = 'https://covid19.mathdro.id/api';
export const fetchData = async () => {
try {
const { data: { confirmed, recovered, deaths, lastUpdate} } = await axios.get(url);
return {confirmed, recovered, deaths, lastUpdate};
} catch (error) {
}
}export const fetchDailyData = async()=> {
try{
const { data } = await axios.get('${url}/daily');
const modifiedData = data.map((dailyData) => ({
confirmed: dailyData.confirmed.total,
deaths: dailyData.deaths.total,
date: dailyData.reportDate,
}));
return modifiedData;
} catch(error){
}
}
As you can see, I am exporting the data from the API in my Index.js file, and in my Chart.jsx is where I set up the empty array for the data to be looped through. Am I incorrectly setting up my empty array or calling the data incorrectly? Some help would be appreciated. Thank you!
EDIT:
Here is the exact error message
TypeError: Cannot read property 'length' of undefined
Chart
src/components/Chart/Chart.jsx:20
17 | fetchAPI();
18 | });
19 |
>20 | const lineChart = (
21 | ^dailyData.length
22 | ? (
23 | <Line
Having inspected the output of the API you are using, I've figured out your mistake.
The output is a JSON array, not an object. So in particular, it has no data property.
So when you do const { data } = await axios.get('${url}/daily'), data will be undefined. Therefore you can't map over it (data.map will be undefined, and you will get an "undefined is not a function" error).
The solution is simple: replace the offending line:
const { data } = await axios.get('${url}/daily')
with
const data = await axios.get('${url}/daily')
(In case you're unsure, the difference between the two lines is that the second one uses data for the entire response - which here is the array you want. The first assumes the response will be an object with a data property, and sets the data variable to be the corresponding value - which doesn't exist here.)
And finally, as I said in my comment, the reason you didn't spot this was those empty catch block in fetchDailyData. Empty catch blocks are a very bad idea in any circumstance - while you certainly don't want your app to blow up with an error for a real end-user, simply silencing the error as you are here is almost never the right solution, instead you should do something to handle the error and either recover from it or let the user know some problem occurred. But here, as you saw, it doesn't even stop an error, it just leads to another one elsewhere, which is necessarily harder to debug. (The error occurred because, when the error is encountered in fetchDailyData, the code inside the try stopped and the catch was executed instead, which does nothing - with the result that the function returns nothing, ie implicitly returns undefined, rather than the array of data you were expecting. And this is why the calling component complains about you trying to access a length property of undefined.)

React Native can not render fetched data. Throws Undefined is not an Object

I'm currently working on react native project.
I'm getting data with axios in componentDidMount function, but data is SOAP way. Therefore I'm changing the data xml to json with xml-js package.
Here is my state;
state = {
contacts: [],
isLoading: true
}
Here is my componentDidMount() function;
componentDidMount() {
xmls = 'my envelope to server.';
Axios.post('my url goes here.', xmls, {
headers: {
'Content-Type': 'text/xml; charset=UTF-8',
'Authorization': 'my key',
'SOAPAction': "my action"
}
}).then(response => {
return response.data;
}).then((res) => {
const options = {
compact: true,
ignoreDeclaration: true,
spaces: 4,
ignoreAttributes: true,
textFn: this.removeJsonTextAttribute,
elementNameFn: function (val) { return val.replace('SOAP-ENV:', '').replace('ns:', ''); } //removes 'SOAP-ENV: and ns: tags from SOAP data.
}
// converting string xml to string json.
let xmlToJSON = convert.xml2json(res, options);
// converting string to json with JSON.parse()
return contactsObj = JSON.parse(xmlToJSON);
}).then((fin) =>{
this.setState({contacts: fin, isLoading: false});
}).catch(err => {
console.warn('Error', err);
});
}
Here is my render function;
render() {
let arr = [];
arr.push(this.state.contacts);
let {isLoading} = this.state;
let res = arr.map((item, i)=> {
return <AnnounceList headLine = {item[0].Envelope.Body.a.b.c[i]} />
});
return (
<View style = {{flex: 1}}>
<TopBar name={"Iletisim"} bColor={"#29303c"} miniLogo={require('../../../assets/pictures/Ikon07-tip2-0.png')} />
<Spinner loading = {isLoading} color = '#29303c'>
<ScrollView>
{res}
</ScrollView>
</Spinner>
</View>
);
}
For rendering my data I'm creating an array instance and push my state contacts data to there. But when I'm trying to select data from array it is throwing me undefined is not an object error. Data is valid until Envelope but after Envelope.Body it throws an error. I didn't understand why it is throwing? Any idea. Thanks for all contribution.
Added Information!!
In my state, contacts is an array. but in my render function when I try to
this.state.contacts.map() it throws me undefined is not function so I checked out what is type of it with console.log(typeof this.state.contacts) it returns object. Why did it become an object? Mustn't it stay as an array?
I think the problem is here
let res = arr.map((item, i)=> {
return <AnnounceList headLine = {item[0].Envelope.Body.a.b.c[i]} />
});
You are looping through all item you have and you are taking item[0]? why?
Then you are taking i which is index of element. Why not to use item?
Adding something like:
let res = arr.map((item, i)=> {
return <div>JSON.stringify(item)</div>
});
will help you with debugging. You can also make your json more beautifull with:
return <div><pre>{JSON.stringify(item, null, 2) }</pre></div>;

Categories