How to display image in reactjs? - reactjs

I have imported the import { Avatar } from '#material-ui/core'; to display the image using the avatar
const TheHeader = () => {
let _UsersId = localStorage.getItem("UsersId")
const classes = useStyles();
const [reRender, setRerender] = useState(false);
const [profilepic, setprofilepic] = useState();
const getProfile = async () => {
const response = await Profile(_UsersId);
setprofilepic(response.data)
}
useEffect(() => {
getProfile();
}, [reRender, profilepic]);
.....
<Avatar alt="" src={profilepic} className={classes.avatar}/>
the result is like this (current)
desired result
result from api console.log(response)

Currently what is being displayed is the fallback image by the Avatar component of material ui.
This is maybe because the image url you are serving it, might be being fetched AFTER your Avatar component has loaded.
The solution to this would - reload the Avatar component using useEffect with image URL set as an observable.
Sample code :
const TheHeader = () => {
let _UsersId = localStorage.getItem("UsersId")
const classes = useStyles();
const [profilepic, setprofilepic] = useState();
const getProfile = async () => {
const response = await Profile(_UsersId);
setprofilepic(response.data[0].ProfilePhoto)
}
useEffect(() => {
getProfile();
}, [profilepic]);
.....
<Avatar alt="" src={profilepic} className={classes.avatar}/>
Now, once your img url is fetched from the endpoint, your component will reload with the correct image in place

Update getProfile function to create objectUrl from binary data:
const getProfile = async () => {
const response = await Profile(_UsersId);
const buffer = new Uint8Array(response.data)
const blob = new Blob([buffer])
setprofilepic(URL.createObjectURL(blob))
}

Related

How to automatically refresh getstream.io FlatFeed after a new post using reactjs?

I would like to understand how can I auto-update the feed after submitting the form through the StatusUpdateForm component. At the moment I have to refresh the page to see the changes.
In general, my task is to differentiate feeds based on the user's location, I requested extended permissions from support so that different users can post to one feed, and therefore I use the modified doFeedRequest parameters of the FlatFeed component to show the feed without being tied to the current user and it works.
I do not use notification, I want the posted messages to appear immediately in the feed.
If I wrote my own custom feed (FeedCustom) component to display data, it would work fine, but how do I make it work with FlatFeed of getstream.io? Any help would be greatly appreciated.
import React, { useEffect, useState } from 'react';
import { StreamApp, FlatFeed, StatusUpdateForm } from 'react-activity-feed';
import 'react-activity-feed/dist/index.css';
// import FeedCustom from './FeedCustom';
const STREAM_API_KEY = 'XXXXXXXXXXXXXXXX';
const STREAM_APP_ID = 'XXXXX';
const App = () => {
const [userToken, setUserToken] = useState(null);
const [loading, setLoading] = useState(true);
const [locationId, setLocationId] = useState(null);
const [data, setData] = useState([]);
const callApi = async () => {
const response = await fetch('https://localhost:8080/user-token')
const userResponse = await response.json();
return userResponse;
};
useEffect(() => {
callApi()
.then(response => {
const resp = JSON.parse(response.body);
setLoading(false);
setUserToken(resp.userToken);
setLocationId(resp.locationId);
})
.catch(e => alert(e));
}, []);
const customDoFeedRequest = (client, feedGroup = 'timeline', userId = locationId, options) => {
const feed = client.feed(feedGroup, userId);
const feedPromise = feed.get(options);
feedPromise.then((res) => {
setData((data) => res.results);
});
return feedPromise;
}
return loading ? (
<div>.... Loading ....</div>
) : (
<StreamApp
apiKey={STREAM_API_KEY}
appId={STREAM_APP_ID}
token={userToken}
>
{/* <FeedCustom dataFeed={ data } /> */}
<FlatFeed doFeedRequest={customDoFeedRequest} />
<StatusUpdateForm
userId={locationId}
feedGroup={'timeline'}
onSuccess={(post) => setData((data) => [...data, post])}
/>
</StreamApp>
)
};
export default App;
My backend https://localhost:8080/user-token returns an object kind of:
{
userToken: 'XXXXXXX'
locationId: 'XXXXXXX'
}

Take a picture and record video react native

My goal is to record a video when holding down the camera button but also take a picture when tapping the camera button. Any idea what I'm doing wrong?
const [video, setVideo] = useState(null);
const [recording, setRecording] = useState(false);
const cameraRef = createRef();
const onLongPressButton = () => {
setRecording(true);
startRecord();
};
const startRecord = async () => {
setRecording(true);
console.log("RECORDING");
if (cameraRef.current) {
setRecording(true);
const recordedVideo = await cameraRef.current.recordAsync();
setVideo(recordedVideo);
}
};
const stopRecord = async () => {
await cameraRef.current.stopRecording();
console.log("STOP RECORDING");
setRecording(false);
};
const handlePhoto = async () => {
if (cameraRef.current && !recording) {
let photo = await cameraRef.current.takePictureAsync({});
console.log(photo.uri);
} else {
stopRecord();
}
};
And here is my camera button component:
<Circle
onPress={handlePhoto}
onLongPress={onLongPressButton}
onPressOut={async () => {
await cameraRef.current.stopRecording();
console.log("STOP RECORDING");
setRecording(false);
}}
delayLongPress={50}
/>
The issue appears to be not with the camera or touch handling, but with the use of createRef instead of useRef. Note that in your case, used within a function component, createRef will create a new ref on every render. Replace it with useRef so that the reference remains the same across renders:
const cameraRef = useRef();

TypeError: urls.map is not a function in React

I have to issue in displaying the image in react. List of all Image urls in get from firebase storage.Passing all the urls display the image shows urls.map is not a function
const ViewImages = () => {
var storageRef = firebase.storage().ref("images/");
const [image, setImage] = useState("");
const [urls, setFiles] = useState("");
const [imageUrl, setImageUrl] = useState([]);
useEffect(() => {
const fetchImages = async () => {
let result = await storageRef.child('images1/').listAll();
let urlPromises = result.items.map(imageRef => imageRef.getDownloadURL());
return Promise.all(urlPromises);
//console.log(urlPromises);
}
const loadImages = async () => {
const urls = await fetchImages();
setFiles(urls);
console.log(urls[0]);
}
loadImages();
}, []);
return(
{urls.map((urls,i) => (
<img src={urls} key={i}/>
))}
</div>
);
}
export default ViewImages;
The issue is you're calling the map method on an empty string ('') which is the initial value of urls. Set it to an empty array instead.
const [urls, setFiles] = useState([])

paginating requests to an API, using HackerNews API

*** The question is quite simple, I just wrote a lot to be specific. ***
I've been looking online for a few hours, and I can't seem to find answer. Most pagination is about after you have received the data from the API call, or for backend node.js built with it's own server.
My issue, I have an API request that returns an array of 500 ID's. Then a second multi API call, looping through each ID making a promise API call. I use the Promise.all method.
It takes 2-3 minutes to complete this request.
Currently, I made a quick filter to get the first ten results, so it'll display and I can render the data to work on other things like the render component and styling.
My question, I'd like to be able to paginate the data while API calls are still being made.
Basically, Promise.all send an array of 10 id's (ten API calls), get continually. But after the first set of ten, I'd like to start receiving the data to render.
Right now, I can only get ten with my filter method. Or wait 2-3 min for all 500 to render.
Here is my request.js file, (it's part of my App component, I just separated it for clarity).
import axios from 'axios';
import BottleNeck from 'bottleneck'
const limiter = new BottleNeck({
maxConcurrent: 1,
minTime: 333
})
export const Request = (setResults, searchBarType, setLoading) => {
const searchBar = type => {
const obj = {
'new': 'newstories',
'past': '',
'comments': 'user',
'ask': 'askstories',
'show': 'showstories',
'jobs': 'jobstories',
'top': 'topstories',
'best': 'beststories',
'user': 'user'
}
return obj[type] ? obj[type] : obj['new'];
}
let type = searchBar(searchBarType)
const getData = () => {
const options = type
const API_URL = `https://hacker-news.firebaseio.com/v0/${options}.json?print=pretty`;
return new Promise((resolve, reject) => {
return resolve(axios.get(API_URL))
})
}
const getIdFromData = (dataId) => {
const API_URL = `https://hacker-news.firebaseio.com/v0/item/${dataId}.json?print=pretty`;
return new Promise((resolve, reject) => {
return resolve(axios.get(API_URL))
})
}
const runAsyncFunctions = async () => {
setLoading(true)
const {data} = await getData()
let firstTen = data.filter((d,i) => i < 10);
Promise.all(
firstTen.map(async (d) => {
const {data} = await limiter.schedule(() => getIdFromData(d))
console.log(data)
return data;
})
)
.then((newresults) => setResults((results) => [...results, ...newresults]))
setLoading(false)
// make conditional: check if searchBar type has changed, then clear array of results first
}
runAsyncFunctions()
}
and helps, here's my App.js file
import React, { useState, useEffect } from 'react';
import './App.css';
import { SearchBar } from './search-bar';
import { Results } from './results';
import { Request } from '../helper/request'
import { Pagination } from './pagination';
function App() {
const [results, setResults] = useState([]);
const [searchBarType, setsearchBarType] = useState('news');
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [resultsPerPage] = useState(3);
// Select search bar button type
const handleClick = (e) => {
const serachBarButtonId = e.target.id;
console.log(serachBarButtonId)
setsearchBarType(serachBarButtonId)
}
// API calls
useEffect(() => {
Request(setResults, searchBarType, setLoading)
}, [searchBarType])
// Get current results
const indexOfLastResult = currentPage * resultsPerPage;
const indexOfFirstResult = indexOfLastResult - resultsPerPage;
const currentResults = results.slice(indexOfFirstResult, indexOfLastResult);
// Change page
const paginate = (pageNumber) => setCurrentPage(pageNumber);
return (
<div className="App">
<SearchBar handleClick={handleClick} />
<Results results={currentResults} loading={loading} />
<Pagination resultsPerPage={resultsPerPage} totalResults={results.length} paginate={paginate} />
</div>
);
}
export default App;
I hope it's generic looking enough to follow guide lines. Please ask me anything to help clarify. I've spent 8-10 hours searching and attempting to solve this...
You can continue with your filter, but you have to do some changes, for totalResults props of the component Pagination you have to set 500 rows so the user can select the page he wants because if you set 10 rows, the pages a user can select are 1,2,3,4, but we don't need that we need to put all pages 1 to 34 pages because we have 500 ids. The second point, we need to fetch data from the server by page with a page size equal to 3 we need to pass to Request startIndex and lastIndex to Request.
Request.js
import axios from 'axios';
import BottleNeck from 'bottleneck'
const limiter = new BottleNeck({
maxConcurrent: 1,
minTime: 333
})
export const Request = (setResults, searchBarType, setLoading, startIndex, lastIndex) => {
const searchBar = type => {
const obj = {
'new': 'newstories',
'past': '',
'comments': 'user',
'ask': 'askstories',
'show': 'showstories',
'jobs': 'jobstories',
'top': 'topstories',
'best': 'beststories',
'user': 'user'
}
return obj[type] ? obj[type] : obj['new'];
}
let type = searchBar(searchBarType)
const getData = () => {
const options = type
const API_URL = `https://hacker-news.firebaseio.com/v0/${options}.json?print=pretty`;
return new Promise((resolve, reject) => {
return resolve(axios.get(API_URL))
})
}
const getIdFromData = (dataId) => {
const API_URL = `https://hacker-news.firebaseio.com/v0/item/${dataId}.json?print=pretty`;
return new Promise((resolve, reject) => {
return resolve(axios.get(API_URL))
})
}
const runAsyncFunctions = async () => {
setLoading(true)
const {data} = await getData()
let ids = data.slice(firstIndex, lastIndex+1) // we select our ids by index
Promise.all(
ids.map(async (d) => {
const {data} = await limiter.schedule(() => getIdFromData(d))
console.log(data)
return data;
})
)
.then((newresults) => setResults((results) => [...results, ...newresults]))
setLoading(false)
// make conditional: check if searchBar type has changed, then clear array of results first
}
runAsyncFunctions()
}
App.js
import React, { useState, useEffect } from 'react';
import './App.css';
import { SearchBar } from './search-bar';
import { Results } from './results';
import { Request } from '../helper/request'
import { Pagination } from './pagination';
function App() {
const [results, setResults] = useState([]);
const [searchBarType, setsearchBarType] = useState('news');
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [resultsPerPage] = useState(3);
// Select search bar button type
const handleClick = (e) => {
const serachBarButtonId = e.target.id;
console.log(serachBarButtonId)
setsearchBarType(serachBarButtonId)
}
// API calls
useEffect(() => {
Request(setResults, searchBarType, setLoading, 0, 2) //we fetch the first 3 articles
}, [searchBarType])
// Change page
const paginate = (pageNumber) => {
// Get current results
const indexOfLastResult = currentPage * resultsPerPage;
const indexOfFirstPost = indexOfLastResult - resultsPerPage;
Request(setResults, searchBarType, setLoading, indexOfFirstPost , indexOfLastResult) //we fetch the 3 articles of selected page
setCurrentPage(pageNumber);
}
return (
<div className="App">
<SearchBar handleClick={handleClick} />
<Results results={results} loading={loading} />
<Pagination resultsPerPage={resultsPerPage} totalResults={500} paginate={paginate} />
</div>
);
}
export default App;

Reload component with react hooks

I would like to ask you how to reload a component after modifying the data of a form, then I have my component:
export default function MyComponent() {
const url = "/api/1";
const [resData, setResData] = useState(null);
useEffect(() => {
const jwt = getJwt();
const fetchData = async () => {
const resP = await axios(url);
setResData(resP.data);
};
fetchData();
}, []);
return <EditComponent={resData} />
}
This component passes my data to the "EditCompoent" child component in which there is a form that is filled with data from the parent component that I can modify in which there is a save button that when I click allows me to send the modified data to my beckend:
const handleConfirm = () => {
axios.put(url, data).then((res) => {
//Reload Component
})
}
I would like to be able to reload the parent component as soon as this works is successful what could I do? I don't want to reload the whole page I just want to reload the parent component that is "MyComponent", I hope I have well posed the problem.
I'd pass the whole useEffect callback down so that handleConfirm can call it again after the axios.put, after which the resData state in the parent will be updated:
export default function MyComponent() {
const url = "/api/1";
const [resData, setResData] = useState(null);
const tryLoginJWT = () => {
const jwt = getJwt();
const resP = await axios(url);
setResData(resP.data);
};
useEffect(tryLoginJWT, []);
return <EditComponent {...{ resData, tryLoginJWT }} />
}
const handleConfirm = () => {
axios.put(url, data)
.then(tryLoginJWT)
.catch(handleErrors); // don't forget to catch here in case there's a problem
}

Resources