react manage query string called data - reactjs

I don't know how to manage query string to react.
I made component class and it is composed of 3 other components.
It is not show data first time. Users have to select or click but
ton.
It is work well.
But I received a new feature. ;(
When users connect my site who copied url, the page has to show data immediately.
So I added query string. But I don't know when I call function.
I installed query-string.
I tried to use 'shouldComponentUpdate' function, but it was not work.
shouldComponentUpdate(nextProps, nextState) {
if (this.props.location.search.ids !== nextProps.location.search.ids) {
// call some function....
}
return true;
}
for example,
Users connect localhost:3000/my/home
It's ok.
But users connect localhost:3000/my/home?ids=1
It's not ok.
Summary.
I want to show data immediately when user connect to the site by query-string.

to fetch data, the most common way to call api is calling in componentDidMount.
https://reactjs.org/docs/faq-ajax.html
if you are using react-router for your app, you can easily get query string with following feature of react-router .
https://reacttraining.com/react-router/web/example/query-parameters
and then pass query string to your api.

I added componentDidMount and call myfunction.
componentDidMount(){
const query = queryString.parse(this.props.location.search);
if(query.ids !== 'undefined'){
let slice_ids = [];
slice_ids = query.ids.split(',');
if(slice_ids.length > 0){
this.myfunction(1);
}
}
}
Users can access the url.
Thanks #gnujoow

Related

Specifically, how does Reactjs retrieve data from firebase function triggers?

I am using express to create my firebase functions, and I understand how to create regular callable functions. I am lost however on the exact way to implement trigger functions for the background (i.e. onCreate, onDelete, onUpdate, onWrite), as well as how Reactjs in the frontend is supposed to receive the data.
The scenario I have is a generic chat system that uses react, firebase functions with express and realtime database. I am generally confused on the process of using triggers for when someone sends a message, to update another user's frontend data.
I have had a hard time finding a tutorial or documentation on the combination of these questions. Any links or a basic programmatic examples of the life cycle would be wonderful.
The parts I do understand is the way to write a trigger function:
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
.onWrite((change, context) => {
// Only edit data when it is first created.
if (change.before.exists()) {
return null;
}
// Exit when the data is deleted.
if (!change.after.exists()) {
return null;
}
// Grab the current value of what was written to the Realtime Database.
const original = change.after.val();
console.log('Uppercasing', context.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return change.after.ref.parent.child('uppercase').set(uppercase);
});
But I don't understand how this is being called or how the data from this reaches frontend code.
Background functions cannot return anything to client. They run after a certain event i.e. onWrite() in this case. If you want to update data at /messages/{pushId}/original to other users then you'll have to use Firebase Client SDK to listen to that path:
import { getDatabase, ref, onValue} from "firebase/database";
const db = getDatabase();
const msgRef = ref(db, `/messages/${pushId}/original`);
onValue(msgRef, (snapshot) => {
const data = snapshot.val();
console.log(data)
});
You can also listen to /messages/${pushId} with onChildAdded() to get notified about any new node under that path.

Remove item using its location or key in Firebase React

I have a simple react application and I am able to add data to it, but I am not sure how to remove/update data.
the main problem is in getting the part where I tell firebase which data to remove. how do I tell that to firebase.
I am using react.
I have been trying out different things but it's just not working
handleRemove(){
console.log('you reached handleRemove function');
var ref =firebase.database().ref('items');
ref.on('value',this.handlegetData,this.handleErrData);
['items']['KpAmo20xP6HPXc7cwjY'].remove();
//itemsRef.remove('KpAmo20xP6HPXc7cwjY');
}
Please tell me how to do this.
My firebase database looks somewhat like this
You need something like that to remove value :
handleRemove() {
return firebase.database().ref('items').child('ITEM_KEY').remove();
}
or something like that to update value :
handleUpdate() {
var updates = {};
updates['/id'] = 1;
updates['/title'] = 'Apple';
return firebase.database().ref('items').child('ITEM_KEY').update(updates);
}
(In your screenshot items is equal to firebase-test)
Here the Firebase Realtime Database documentation.

share() vs ReplaySubject: Which one, and neither works

I'm trying to implement short-term caching in my Angular service -- a bunch of sub-components get created in rapid succession, and each one has an HTTP call. I want to cache them while the page is loading, but not forever.
I've tried the following two methods, neither of which have worked. In both cases, the HTTP URL is hit once for each instance of the component that is created; I want to avoid that -- ideally, the URL would be hit once when the grid is created, then the cache expires and the next time I need to create the component it hits the URL all over again. I pulled both techniques from other threads on StackOverflow.
share() (in service)
getData(id: number): Observable<MyClass[]> {
return this._http.get(this.URL)
.map((response: Response) => <MyClass[]>response.json())
.share();
}
ReplaySubject (in service)
private replaySubject = new ReplaySubject(1, 10000);
getData(id: number): Observable<MyClass[]> {
if (this.replaySubject.observers.length) {
return this.replaySubject;
} else {
return this._http.get(this.URL)
.map((response: Response) => {
let data = <MyClass[]>response.json();
this.replaySubject.next(data);
return data;
});
}
}
Caller (in component)
ngOnInit() {
this.myService.getData(this.id)
.subscribe((resultData: MyClass[]) => {
this.data = resultData;
},
(error: any) => {
alert(error);
});
}
There's really no need to hit the URL each time the component is created -- they return the same data, and in a grid of rows that contain the component, the data will be the same. I could call it once when the grid itself is created, and pass that data into the component. But I want to avoid that, for two reasons: first, the component should be relatively self-sufficient. If I use the component elsewhere, I don't want to the parent component to have to cache data there, too. Second, I want to find a short-term caching pattern that can be applied elsewhere in the application. I'm not the only person working on this, and I want to keep the code clean.
Most importantly, if you want to make something persistent even when creating/destroying Angular components it can't be created in that component but in a service that is shared among your components.
Regarding RxJS, you usually don't have to use ReplaySubject directly and use just publishReplay(1, 10000)->refCount() instead.
The share() operator is just a shorthand for publish()->refCount() that uses Subject internally which means it doesn't replay cached values.

My flux store gets re-instantiated on reload

Okay. I'm kinda new to react and I'm having a #1 mayor issue. Can't really find any solution out there.
I've built an app that renders a list of objects. The list comes from my mock API for now. The list of objects is stored inside a store. The store action to fetch the objects is done by the components.
My issue is when showing these objects. When a user clicks show, it renders a page with details on the object. Store-wise this means firing a getSpecific function that retrieves the object, from the store, based on an ID.
This is all fine, the store still has the objects. Until I reload the page. That is when the store gets wiped, a new instance is created (this is my guess). The store is now empty, and getting that specific object is now impossible (in my current implementation).
So, I read somewhere that this is by design. Is the solutions to:
Save the store in local storage, to keep the data?
Make the API call again and get all the objects once again?
And in case 2, when/where is this supposed to happen?
How should a store make sure it always has the expected data?
Any hints?
Some if the implementation:
//List.js
componentDidMount() {
//The fetch offers function will trigger a change event
//which will trigger the listener in componentWillMount
OfferActions.fetchOffers();
}
componentWillMount() {
//Listen for changes in the store
offerStore.addChangeListener(this.retriveOffers);
}
retrieveOffers() {
this.setState({
offers: offerStore.getAll()
});
}
.
//OfferActions.js
fetchOffers(){
let url = 'http://localhost:3001/offers';
axios.get(url).then(function (data) {
dispatch({
actionType: OfferConstants.RECIVE_OFFERS,
payload: data.data
});
});
}
.
//OfferStore.js
var _offers = [];
receiveOffers(payload) {
_offers = payload || [];
this.emitChange();
}
handleActions(action) {
switch (action.actionType) {
case OfferConstants.RECIVE_OFFERS:
{
this.receiveOffers(action.payload);
}
}
}
getAll() {
return _offers;
}
getOffer(requested_id) {
var result = this.getAll().filter(function (offer) {
return offer.id == requested_id;
});
}
.
//Show.js
componentWillMount() {
this.state = {
offer: offerStore.getOffer(this.props.params.id)
};
}
That is correct, redux stores, like any other javascript objects, do not survive a refresh. During a refresh you are resetting the memory of the browser window.
Both of your approaches would work, however I would suggest the following:
Save to local storage only information that is semi persistent such as authentication token, user first name/last name, ui settings, etc.
During app start (or component load), load any auxiliary information such as sales figures, message feeds, and offers. This information generally changes quickly and it makes little sense to cache it in local storage.
For 1. you can utilize the redux-persist middleware. It let's you save to and retrieve from your browser's local storage during app start. (This is just one of many ways to accomplish this).
For 2. your approach makes sense. Load the required data on componentWillMount asynchronously.
Furthermore, regarding being "up-to-date" with data: this entirely depends on your application needs. A few ideas to help you get started exploring your problem domain:
With each request to get offers, also send or save a time stamp. Have the application decide when a time stamp is "too old" and request again.
Implement real time communication, for example socket.io which pushes the data to the client instead of the client requesting it.
Request the data at an interval suitable to your application. You could pass along the last time you requested the information and the server could decide if there is new data available or return an empty response in which case you display the existing data.

How to make initial authenticated request with token from local storage?

I'm using vanilla flux with some utils for communicating with my APIs.
On initial page load I'd like to read some token from local storage and then make a request to my API to get my data.
I've got a LocalStorageUtils.js library for interacting with window.localStorage. My container component handles all login/logout actions and reads the current user on page load.
App.js
componentWillMount() {
LocalStorageUtils.get('user');
}
LocalStorageUtils reads the value and brings it into Flux via ServerAction similar to the flux chat example.
get(key) {
var value = window.localStorage.getItem(key);
if (value) {
ServerActionCreators.receiveFromLocalStorage(key, value);
}
}
That puts the user into my UserStore and into my views where I can show the username and some logout link, etc.
I also have ApiUtils.js for requesting data from the server. So the question is: Where do I tell my ApiUtils that I have a logged-in user at initial page load?
I could call some method inside ApiUtils from my LocalStorageUtils but that does not feel right.
Or do I have to make another round trip whenever I get a change event inside my container component?
You should pass the user as data to your ApiUtils class and removing the need from being concerned about how your ApiUtils is used.
var ApiUtils = function () {
this.get = function (endpoint, data) {
return theWayYouSendAjaxRequests.get(endpoint).setData(data);
};
};
// Wherever your ApiUtils is used.
var api = new ApiUtils();
api.get('/me', {user: userFromStore});
I found a solution that works and feels right.
As getting data from local storage is synchronous there is no need to pipe it through Flux via ServerActionCreators. Simply use LocalStorageUtils to get the current user and call the login method with that user. The login Action is the same you would use when a user initially logs in. login triggers getting new data from server. The new data is saved in my DataStore and the user is saved to my UserStore.
Thanks for all hints at Twitter and at https://reactiflux.slack.com/.

Resources