How can i pass data from promise to props in react - reactjs

I'm new to react and I want to pass my data from my securestore to props. But I don't now how to correctly handle the promise function and extract the data of it.
When I pass the data like this, my object is undefined.
Here is my code.
const Authenticate = () => {
//const [deviceId, setDeviceId] = useState("");
//SecureStore.deleteItemAsync("device_id").then((reject) => {
//});
//const resp = {code : 3, expositions : 5}
SecureStore.getItemAsync("device_id").then((response) => {
//setDeviceId({"id" : response});
console.log("stored id : " + response);
//let resp = sendId({'id' : response})
test(response);
}
);
function test (info){
return info;
}
return (
<Expositions infections={test()}/>
);
};
export default Authenticate;

you should really read this
const Authenticate = () => {
const [myStuff, setMyStuff] = useState();
//this will be executed on mount
useEffect(()=>{
SecureStore.getItemAsync("device_id").then((response) => {
setMyStuff(response)
}
);
},[])
console.log(myStuff)
}
on first render myStuff is undefined, then after fetching your data, setMyStuff will trigger a new render and you'll see the updated data

Use react state hook to store the data provided by promise and then pass the state to the rendered jsx.

Related

Rendering different elements based on promise's result

I'm trying to make a login/logout button based on my user authentication status. since I'm fetching this data from my api, I cant seem to return the data itself, only the promise and since in reactjs the .then() function cant be used I don't know how to access the data I need.
this is the function that fetches the data from api, I want it to return "data.success" which is a boolean, but instead a promise is returned.
let checkAuth = () => {
return fetch('/v1/checkLogin')
.then(response => response.json())
.then(data => {
return data.success
})
}
react code calling above function :
{
(checkAuth())
? <button>logout</button>
: <button>login</button>
}
any help is appreciated =)
Due to the asynchronous nature of requests, the outer code will have already returned before the promise is resolved. That is why it returns a promise instead of your data.
A better approach to get through this is to use "useState" "useEffect" hooks
use "useEffect" to fetch the data when the component renders for the first time
use "useState" store the fetched data to a variable and use it in ways you want
export default LoginComponent = () => {
const [authenticated, setAuthenticated] = useState(false); // False initially
let checkAuth = () => {
const result = await fetch("/v1/checkLogin") // Wait for promise to resolve
const data = result.json();
setAuthenticated(data.success); // Set Data. (You can set just "data" if you want the whole data object)
};
// useEffect which fires once when the component initially renders
useEffect(() => {
checkAuth()
}, []);
return (
<div>
{authenticated ? <button>logout</button> : <button>login</button
</div>
);
};
You can use a state with useEffect to update the UI accordingly
const YourComponent = () => {
const [isAccess, setIsAccess] = useState(); // initialize your state
let checkAuth = () => {
return fetch("/v1/checkLogin")
.then((response) => response.json())
.then((data) => {
setIsAccess(data.success); //set the value for your state
});
};
useEffect(() => {
checkAuth()
}, [])
//after the state update, your UI will be re-rendered with the latest value which you expected
return (
<div>{isAccess ? <button>logout</button> : <button>login</button>}</div>
);
};

React state is never up to date in my callback

In a react functional component, I setState from an api call. I then create an EventSource that will update the state each time an event is received.
The problem is that in the EventSource callback, the state is not updated.
My guess is, state is printed at the creation of the callback, so it can't be updated.
Is there any other way to do it ?
function HomePage() {
const [rooms, setRooms] = useState<Room[]>([]);
const getRooms = async () => {
const data = await RoomService.getAll(currentPage);
setRooms(data.rooms);
}
const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
console.log(rooms); // rooms is always empty
// will append or remove a room via setRooms but i need actual rooms first
}
useEffect(() => {
// setState from api response
getRooms();
// set up EventSource
const url = new URL(process.env.REACT_APP_SSE_BASE_URL ?? '');
url.searchParams.append('topic', '/room');
const eventSource = new EventSource(url);
eventSource.onmessage = e => updateRooms(JSON.parse(e.data));
}, [])
...
}
Try using a functional update when using setRooms like this:
const updateRooms = (data: AddRoomPayload | DeleteRoomPayload) => {
setRooms((rooms) => {
if (data.type === 'add') {
return [...rooms, data.room];
} else if (data.type === 'remove') {
return rooms.filter(/* ... */);
}
});
}
Here is a reference to the React Docs on functional updates in useState: https://reactjs.org/docs/hooks-reference.html#functional-updates
If that doesn't work then try checking the React Developer Tools to make sure that the component's state rooms is being updated.

Data from function is null on first load

I'm using a function from another file to get data from a Firebase. However, the first time I load the app, I don't get the data. Data pulls it out fine. When I write to the console right after adding it to a variable, I see them. However, Return does not return them and returns only an empty field.
If I edit and save the file after loading, the application is refreshed and the data is loaded. Is this solution correct? Then I want to have more functions there.
const Page = () => {
const [categories, setCategories] = useState([]);
const fetchMainCategories = async () => {
const results = placesB.getMainCategories();
setCategories(results);
};
useEffect(() => {
fetchMainCategories();
}, []);
}
export default Page;
class Categories {
getMainCategories(){
let val = [];
const reference = query(ref(db, 'categories/1/'));
onValue(reference, (snapshot) => {
val = snapshot.val();
console.log(val); // It always lists the data here
});
return val; // HERE IS THE PROBLEM. On the first load is this empty!
}
}
const cats = new Categories();
export default cats;
Is here anyone who can help me please?
The onValue() returns data asynchronously and hence the array is always returned empty. Since you need to fetch data only once, use get() instead of onValue():
class Categories {
// async
async getMainCategories() {
const reference = query(ref(db, 'categories/1/'));
const snap = await get(reference);
return snap.val();
}
}
Then you call this method as shown below:
const fetchMainCategories = async () => {
// await here
const results = await placesB.getMainCategories();
console.log(results);
setCategories(results);
};
Try to put a condition, as if(val) then return val....

ReactJs can't get async content form api call in useEffect and use it later in component

I'm lost. I've tried almost all I know. In my other component, similar process works fine, but in this one there is something obviously wrong implemented.
I have a Context Provider, and set two values to share, a function to call an Api and retrieve a list of contacts (getContactsList), and a variable where I put that list of contacts (contactsList).
I call getContactsList in useEffect. Later, I can use contactsList variable, but is always an empty array. I know that the problem is related to Promises and async functions maybe, but I can't find the mistake in my code.
I left here a copy of the components, starting for the view component that has the problem:
Detail Component:
function ContactDetail() {
const { getContactsList, contactsList } = useContext(ContactsContext);
const { id } = useParams();
useEffect(() => { getContactsList().catch(null) }, []);
const contact = contactsList?.filter(c => {
return (Number(c.id) === Number(id))
});
return (
<div>
{contact? "contact finded" : "contact not finded"}
</div>
);
}
ApiCall
async function apiCall (
url,
method = "get",
body,
headers)
{
try {
const response = await fetch(url, {
method,
body,
headers
});
const r = await response.json();
return r;
}
catch (err) {
Promise.reject(err);
}
}
Provider
function ContactsProvider({ children }) {
const [ contactsList,setContactsList ] = useState([]);
const getContactsList = async () => {
try {
const contactsResult = await apiCall("https://fakeurl.com");
setContactsList(contactsResult);
}
catch(err) {
setContactsList([]);
}};
return (
<ContactsContext.Provider value={{getContactsList, contactsList}}>
{children}
</ContactsContext.Provider>
);
}
Also, the code is in my GitHub: https://github.com/thenablyn/local-search-browser.git
This code doesn't seem to be in your repo, but I've tested what you've written and it seems to work, is there a chance the id coming from useParams isn't matching any of the contacts when you're filtering?
The error was that I forgot to get the first element when I did the array.filter() method. It's a Jr mistake.
The code in that assignment has to be like this:
const [contact] = contactsList.filter(...); //this get the first element and assign to constant "contact"

How can I call function even before useState?

I have a context state that contains that is on page UserState.js
data: null
columns: null
And I am calling it via useContext on UserTable.js
const userContext = useContext(UserContext);
const {data,columns} = userContext;
And for what is inside the data and columns, it will be extracted by calling API via axios.
I am facing difficulty is that, for the particular page, I also have a localData and localColumns that is
const [localColumns, setlocalColumns] = useState([...columns]);
const [localData, setlocalData] = useState([...data]);
Where because when calling it, the data is still null and hence it returns error.
I have tried extraction from the database using useEffect and/or useLayout
The overall file structure is like this
-src
--components
---context
----user
-----UserState.js
--pages
---UserPage
----UserTable.js
And the UserTable.js looks like this
const UserTable = () => {
useLayoutEffect(() => {
{
getAllUser();
}
});
const { data, columns,setAllUserFunc } = userContext;
const getAllUser = () => {
axios
.get("http://localhost:3000/v1/users", {
headers: {
Authorization: "Bearer " + token.access.token,
},
})
.then((response) => {
let allUser = response.data.results;
let allNormalUser = allUser.filter((user) => user.role == "user");
setAllUserFunc(allNormalUser);
})
.catch((error) => {});
};
const [localColumns, setlocalColumns] = useState([...columns]);
const [localData, setlocalData] = useState([...data]);
return (
<Table columns={columns} dataSource={data} />
)
}
The setAllUserFunc will set the data and columns to be their corresponding that is on the UserState.js and I confirm it is working (by commenting on the localData and localColumns as well as table).
My question is how can I call the function before the useState that set localColumns?
useEffect and useLayoutEffect don't work

Resources