I'm using the react-native-render-html npm package with expo. I'm trying to fetch some data from a website in useEffect and use the package to display the contents, however I keep getting the error of No source prop was provided. Nothing will be rendered.
I think the RenderHTML prop is being rendered before the request has been fulfilled:
import React, { useEffect, useState } from 'react'
import { ActivityIndicator, StyleSheet, Text, useWindowDimensions, View } from 'react-native';
import RenderHTML from 'react-native-render-html';
const EventsScreen = () => {
const [eventsHTML, setEventsHTML] = useState(null);
const {width} = useWindowDimensions();
useEffect(()=>{
fetch('https://www.google.com')
.then(response => response.text())
.then(response => {setEventsHTML(response);console.log("render");});
}, [eventsHTML]);
return (
<View>
{!eventsHTML? <ActivityIndicator/> : <RenderHTML contentWidth={width} source={eventsHTML}/>}
</View>
// <Text>The data has {eventsHTML? 'loaded' : 'not loaded'}</Text>
// <RenderHTML contentWidth={width} source={source}>Hello world</RenderHTML>
)
}
export default EventsScreen;
H
for rendering html first set html object like this:
const source = {
html: eventsHTML,
};
then pass this source object as props to RenderHTML component like this:
<RenderHTML contentWidth={width} source={source}/>
Related
I am developing using react.
It is in the process of fetching the information contained in the db and displaying it on the web page through the map method.
If you delete one piece of information using onclick or the onClose method provided by antd, the info is also deleted from the db.
in the db, the function worked successfully. but the information at the bottom is deleted, not the deleted information in the web page.
If I refresh website, it is displayed normally, but I don't want to use the window reload function.
I wonder why this is happening and what is the solution.
thank you!
AlertPage
import React, { useState } from "react";
import useSWR from "swr";
import axios from "axios";
import AlertComponent from "./Sections/AlertComponent";
const fetcher = async (url) =>
await axios.get(url).then((response) => JSON.parse(response.data.alerts));
function AlertPage() {
const { data = [], error } = useSWR("/api/streaming/getAlerts", fetcher, {
refreshInterval: 1000,
});
const onClose = (data) => {
axios.post(`/api/streaming/removeAlerts/${data._id.$oid}`).then(() => {
console.log(`${data._id.$oid} deleted`);
});
};
const renderAlerts = data.map((alert, index) => {
return (
<div key={index}>
<AlertComponent alert={alert} index={index} onClose={onClose} />
</div>
);
});
if (error) return <div>failed to load</div>;
if (data === []) return <div>loading...</div>;
return <div>{renderAlerts}</div>;
}
export default AlertPage;
AlertComponent
import React, { useState } from "react";
import { Alert } from "antd";
import Marquee from "react-fast-marquee";
function AlertComponent(props) {
const [alert, setalert] = useState(props.alert);
const [index, setindex] = useState(props.index);
return (
<div
className="alert"
key={index}
style={{ display: "flex" }}
onClick={() => {
props.onClose(alert);
}}
>
<Alert
message={`${alert.data.timestamp.$date.substr(0, 19)}`}
description={
<Marquee pauseOnHover speed={40} gradient={false}>
{`<${alert.data.location}> <${alert.data.name}> <${alert.data.contents}> detected`}
</Marquee>
}
banner
/>
</div>
);
}
export default AlertComponent;
This could be happening due the local cache maintained by swr and since you're not refetching the data after the deletion the changes are not reflected in the DOM.
One options is to trigger a manual refetch to retrieve the most up-to-date data. We could achieve that by changing the following lines:
const { data = [], error, mutate } = useSWR("/api/streaming/getAlerts", fetcher, {
refreshInterval: 1000
});
...
axios.post(`/api/streaming/removeAlerts/${data._id.$oid}`).then(() => {
mutate("/api/streaming/getAlerts");
});
another approach would be to rely on the optimistic update strategy from swr, there is an example here
I am trying to display dynamic data based on record id coming from useParams hook variable id. But when I concatenated the id value, it returns not found 404 error. Although the id value is returned as valid id when I console it, the concatenation doesn't work.
Here is my code
import React, { useEffect, useRef, useState } from "react";
import SignaturePad from "react-signature-canvas";
import offer from "./assets/offer.PNG";
import { Document, Page } from "react-pdf";
// Import the main component
import { Viewer } from "#react-pdf-viewer/core"; // install this library
// Plugins
import { defaultLayoutPlugin } from "#react-pdf-viewer/default-layout"; // install this library
// Import the styles
import "#react-pdf-viewer/core/lib/styles/index.css";
import "#react-pdf-viewer/default-layout/lib/styles/index.css";
// Worker
import { Worker } from "#react-pdf-viewer/core"; // install this library
import axios from "axios";
import { useParams } from "react-router-dom";
const Signature = (props) => {
const id = useParams();
const [numPages, setNumPages] = useState(null);
const baseURL = "http://127.0.0.1:8000/rent/" + id;
const [datas, setData] = useState([]);
useEffect(() => {
axios
.get(baseURL)
.then((response) => {
setData(response.data);
})
.then(
(response) => {},
(err) => {
console.log("No Data To Show");
}
)
.catch((err) => {
return false;
});
}, []);
// Create new plugin instance
const defaultLayoutPluginInstance = defaultLayoutPlugin();
console.log(docId);
return (
<div className="p-10 flex flex-col space-y-24 font-serif justify-center items-center">
<img src={imgg} />
{datas?.file && (
<>
<Worker workerUrl="https://unpkg.com/pdfjs-dist#2.6.347/build/pdf.worker.min.js">
<Viewer
fileUrl={datas?.file}
plugins={[defaultLayoutPluginInstance]}
/>
</Worker>
</>
)}
</div>
);
};
export default Signature;
Here is the value of id which is dynamically changing.
But when I pass the value of id as follows it works fine.
const baseURL =
"http://127.0.0.1:8000/rent/ce779e1d-3afb-4aa7-82e8-5bf74c4af0a7";
But when I concatenate the id variable it returns 404 not found error.
const baseURL =
"http://127.0.0.1:8000/rent/"+id;
What's my mistake here?
useParams hook of React Router returns an object with params.
You should to use something like that:
const { id } = useParams();
in the case if your params is called id.
More you can see here, in the documentation: https://v5.reactrouter.com/web/api/Hooks/useparams
When I run onPress in TodoItem component, I want scrollTo to be executed and scroll down as much as y: height value
but if i run onPress
node.scrollTo is not a function << this error occure
this is my code
(TodoList.js)
import React, {useContext, useState, useEffect, createRef} from 'react';
import {FlatList} from 'react-native';
import {
Dimensions,
NativeSyntheticEvent,
NativeScrollEvent,
ScrollView,
} from 'react-native';
const TodoList = ({replycomment}) => {
const height = Dimensions.get('window').height;
const [tabIndex, setTabIndex] = useState(0);
const flatListRef = React.useRef()
const refScrollView = createRef();
return (
<FlatList
ref={refScrollView}
style={{height}}
contentOffset={{x: 0, y: height}}
renderItem={({item}) => (
<TodoItem
onPress={() => {
const node = refScrollView.current;
if (node) {
node.scrollTo({x:0, y: height, animated: true});
}
}}
/>
)}
/>
(TodoItem.js)
import React, { useCallback, useState } from 'react';
import {FlatList} from 'react-native';
const TodoItem = ({onPress}) => {
return (
<MainContainer onPress={onPress}>
<Label>hi</Label>
</MainContainer>
i'm not sure why this error happend. how can i fix my code?? i want to use FlatList
From the Github source code of FlatList, I can only see 4 methods which help with scroll functionality :-
scrollToEnd(params?: ?{animated?: ?boolean, ...})
scrollToIndex(params: {
animated?: ?boolean,
index: number,
viewOffset?: number,
viewPosition?: number,
...
})
scrollToItem(params: {
animated?: ?boolean,
item: ItemT,
viewPosition?: number,
...
})
scrollToOffset(params: {animated?: ?boolean, offset: number, ...})
I think you need to make use of either of the above (since FlatList doesn't implement it's own scrollTo). I can see scrollTo usage inside VirtualizedList which is internally returned by FlatList.
Link to the source code - https://github.com/facebook/react-native/blob/master/Libraries/Lists/FlatList.js
Can you try using something like this :
node.scrollIntoView({ behavior: 'smooth', block: 'start' })
Create a loader component and call it from all other component across the project. Where I can pass the loader status and custom message every time I call the loader from different component. Hopefully a function with 2 arguments.
I konw two ways :
Inject the Loader component into the Header or Footer or into the Parent Component and you can call it with [ref][1]
Inject the Loader component into the Header or Footer or into the Parent Component and you can use a shared state lib like reduxto call it
https://codesandbox.io/s/blissful-fast-h5ugs?file=/src/Preloader.js
Something like this:
Parent Component
import React, {useState} from 'react'
import Preloader from './Preloader'
import OtherComponent from './OtherComponent'
const App = () => {
//create loader message in state
const [loader, setLoader] = useState("")
//create message setter
const messageSetter = (message) => {
setLoader(message);
}
//render pre loader on whether loader message exists
//pass messege setter to other components
return (
<div>
{loader && <Preloader message={loader}/>}
<OtherComponent messageSetter={messageSetter} />
</div>
)
}
export default App;
Child Component
import React, { useState } from 'react';
const OtherComponent = ({messageSetter}) => {
const [data, setData] = useState("");
//mock api call
const yourFunction = async () => {
let mockApi = new Promise(function(resolve, reject) {
setTimeout(()=> {
resolve("Your data.");
},2000)
});
//await data
let result = await mockApi;
//set data to state
setData(result);
//close loader
messageSetter('');
}
//call loader with custom message and api call on click
return(
<div>
<button onClick={() => {messageSetter("custom loading message"); yourFunction();}}>Click</button>
<div>{data? data : "No data called."}</div>
</div>
)
}
export default OtherComponent;
Loader Component
import React from 'react';
//if needed give it absolute position via css and raise z index
const Preloader = ({message}) => {
return(
<div>{message}</div>
)
}
export default Preloader;
I have following component where I want to display data from an API, ShopScreen.js. I retrieve data with useEffect hook from API in service folder, and everything is ok, the json data is being loaded into data variable from useState hook, when I console.log it.
I have problem to the display data from this variable with map method. I get the error: Cannot read property 'map' of undefined. Can spot somebody where the problem is?
ShopScreen.js:
import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, Button } from 'react-native';
import { fetchShops } from '../services/fetchShops';
const ShopsScreen = props => {
const [data, setShops] = useState({});
useEffect(() => {
fetchShops()
.then(response => response.json())
.then(data => setShops(data));
}, []);
return(
<View>
<Text>The Shops Screen!</Text>
{data.result.map(shop => {return (<Text>{shop.address}</Text>)})}
</View>
);
};
export default ShopsScreen;
My service for fetching data is fetchShops.js
export const fetchShops = () => {
const URL = `https://vilvumbiyl.execute-api.eu-west-1.amazonaws.com/Dev/store/MEBD/list`;
return fetch(URL)
}
useEffect without any params is equal to componentDidMount and for this reason, is called after the render.
So, the first time your jsx code is called, data.result.map is undefined and only after the re-render, do to the response of fetchShops(), it has a value.
You simply need to check the value like this:
data.result && data.result.map()
You can try:
const [data, setShops] = useState({result : {}});
or test data.result before use map on it.
ShopsScreen returns your view(JSX) before you get answer from your rest API. The result is null. You get the exception.