selectfromresult rtk always undefined - react-redux

// id comes from route and i use rtk query hook
but inquiry always be undefined and i log the data from useGetInquiriesQuery IT WORKS
WHAT IS THE BEST WAY TO DO
const { id } = useParams();
const validate = (input = values) => {
}
const [values, setValues, errors, setErrors, inputChanged] = useForm(initstate, validate)
const {inquiry} =useGetInquiriesQuery(undefined,{
selectFromResult:({data}) =>({
inquiry:data?.find((i)=> i.orderId === id),
}),
})
useEffect(()=>{
if(inquiry){
console.log(inquiry)
}
},[inquiry])

Related

Add and Edit in same component in react

if url is shipping/1245abcde, the form should load with the data comes from dispatch(getOrderDetails(orderId)). It does works fine when loading for first time but when I click refresh in the browser, it shows error at line: setAddress
TypeError: Cannot read property 'shippingAddress' of undefined
Here, I cannot call useSelector inside the useEffect. Is there anyway to get orderDetails state inside the useEffect().
Below is the ShippingScreen components
const ShippingScreen = ({ history, match }) => {
const orderId = match.params.orderId
const dispatch = useDispatch()
const cart = useSelector((state) => state.cart)
const { shippingAddress } = cart
const [address, setAddress] = useState(shippingAddress.address)
const [city, setCity] = useState(shippingAddress.city)
const [postalCode, setPostalCode] = useState(shippingAddress.postalCode)
const [country, setCountry] = useState(shippingAddress.country)
const orderDetails = useSelector((state) => state.orderDetails)
const { order } = orderDetails
useEffect(() => {
if (orderId) {
dispatch(getOrderDetails(orderId))
setAddress(order.shippingAddress.address)
setCity(order.shippingAddress.city)
setPostalCode(order.shippingAddress.postalCode)
setCountry(order.shippingAddress.country)
}
}, [orderId])

how do I unit test this function which handles observables

I have created this function because for all the requests my application sends out using http.post, this is how different parts handle the response. So rather than duplicating the code, I thought to create a function. But I am unable to figure out how to unit test this function.
private editAnswerSubject: Subject<Result>;
subscribeToReturnedObservable(observable:Observable<any>, subject:Subject<Result>) {
observable.subscribe((res) => {
const ev = <HttpEvent<any>>(res);
if (ev.type === HttpEventType.Response) {
const isResponseStructureOK: boolean = this.helper.validateServerResponseStructure(ev.body);
if (isResponseStructureOK) {
const response: ServerResponseAPI = ev.body;
subject.next(new Result(response.result, response['additional-info']));
} else {
subject.next(new Result(messages.error, messages.invalidStructureOfResponse));
}
}
},
(error: ServerResponseAPI) => {
const errorMessage: string = this.helper.userFriendlyErrorMessage(error);
subject.next(new Result(messages.error, errorMessage));
},
() => { // observable complete
});
}
editAnswer(answer: Answer): any {
const observable = this.bs.editAnswer(answer)
this.subscribeToReturnedObservable(observable,this.editAnswerSubject);
}
The test I have written so far is
describe('subscribeToReturnedObservable tests:', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [QuestionManagementService, HelperService, WebToBackendInterfaceService, AuthService, HttpClient, HttpHandler]
});
});
fit('should call send next value for the subject is the response from the server is ok', () => {
const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
const body = {"result":"success", "additional-info":"some additional info"};
const receivedHttpEvent = new HttpResponse({body:body});
let observable = new Observable();
spyOn(observable,'subscribe').and.returnValue(receivedHttpEvent);
spyOn(questionService['editQuestionSubject'],'next');
questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
observable.subscribe();
expect(questionService['editQuestionSubject'].next).toHaveBeenCalled();
});
});
But it get error Expected spy next to have been called.
I did this (hoping that it is the right way). The scope of testing is to check that the Subject's next is called correctly. So create an Observable using of and let the code flow from there.
fit('should call send next value for the subject is the response from the server is ok', () => {
const questionService:QuestionManagementService = TestBed.get(QuestionManagementService);
const helperService:HelperService = TestBed.get(HelperService);
const body = {"result":"success", "additional-info":"some additional info"};
const receivedHttpEvent = new HttpResponse({body:body});
const expectedResult = new Result('success', 'some additional info');
spyOn(helperService,'validateServerResponseStructure').and.returnValue(true);
let observable = of(receivedHttpEvent);
spyOn(questionService['editQuestionSubject'],'next');
questionService.subscribeToReturnedObservable(observable,questionService['editQuestionSubject']);
expect(questionService['editQuestionSubject'].next).toHaveBeenCalledWith(expectedResult);
});

Selector for React-Redux

To use selector, I tried to follow this URL reference: https://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/
One of the example is :
const selectSomeData = state => state.someData;
const selectFilteredSortedTransformedData = createSelector(
selectSomeData,
(someData) => {
const filteredData = expensiveFiltering(someData);
const sortedData = expensiveSorting(filteredData);
const transformedData = expensiveTransformation(sortedData);
return transformedData;
}
)
const mapState = (state) => {
const transformedData = selectFilteredSortedTransformedData(state);
return {
data: transformedData
};
}
Question: Within mapState we are calling selectFilteredSortedTransformedData and we are also passing State as parameter. However, the function itself is not taking any parameter, how does it work?
const selectFilteredSortedTransformedData = createSelector(
did you add mapState function in redux connect function ?? something like this.
export default connect(mapState)(Component)

React redux Thunk - Making two ajax call one after the other with the result from the first ajax call using fetch API

I am trying to make two ajax call one after the other , i.e with the result of the first call data , i am making the second call. I am trying to use thunk , but it is not happening , i am getting errors.
actions.js
const fetchedStateNameSucess = (json) => {
return {
type: 'FETCH_STATE_NAME_SUCCESS',
json
}
}
const fetchProvidersDetailsSuccess = (providersData) => {
return {
type: 'FETCH_PROVIDER_DETAILS_SUCCESS',
providersData
}
}
export const fetchProvidersDetails = (providerId) => {
return (dispatch) => {
const providerUrl = `http://someUrl`;
const stateClientCountUrl = `http://someUrl/${state}`;
fetch(providerUrl)
.then(response => response.json())
.then(json => dispatch(fetchProvidersDetailsSuccess(json)))
.then((stateValue = json[0].stateVal)
fetch(stateClientCountUrl)
dispatch(fetchedStateNameSucess(response)));
};
}
In the above call , fetch(providerUrl) , i am getting response where i am getting the stateval , how to use that in making the second call to fetch(stateClientCountUrl) which takes stateval as a parameter.
As Miguel said you can do your second query in .then() clause as well as you can use async/await syntax, something like this:
export const fetchProvidersDetails = providerId => {
return async dispatch => {
const providerUrl = `http://someUrl`;
try {
const response = await fetch(providerUrl);
const json = await response.json();
dispatch(fetchProvidersDetailsSuccess(json))
const stateClientCountUrl = `http://someUrl/${json[0].stateVal}`;
const response2 = await fetch(stateClientCountUrl);
const json2 = await response2.json();
dispatch(fetchedStateNameSucess(json2));
} catch (error) {
console.log('Error', error);
}
}
If you want to use values from the first call response for the second fetch call, you need to do the second fetch after the first one has succeeded, more or less like this:
export const fetchProvidersDetails = (providerId) => {
return (dispatch) => {
const providerUrl = `http://someUrl`;
const stateClientCountUrl = `http://someUrl/${state}`;
fetch(providerUrl)
.then(response => response.json())
.then(json => {
dispatch(fetchProvidersDetailsSuccess(json));
const stateValue = json[0].stateVal;
fetch(stateClientCountUrl)
.then(response => dispatch(fetchProvidersDetailsSuccess(response)));
})
}
Don't forget to add error handling there, both for HTTP status codes and for JavaScript errors (by adding corresponding catch clauses).

Angularfire2 & Firestore – retrieve all subcollection content for a collection list

I try to retrieve datas in a subcollection based on the key received on the first call.
Basically, I want a list of all my user with the total of one subcollection for each of them.
I'm able to retrieve the data from the first Payload, but not from pointRef below
What is the correct way to achieve that?
getCurrentLeaderboard() {
return this.afs.collection('users').snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data()
const id = a.payload.doc.id;
const pointRef: Observable<any> = this.afs.collection('users').doc(`${id}`).collection('game').valueChanges()
const points = pointRef.map(arr => {
const sumPoint = arr.map(v => v.value)
return sumPoint.length ? sumPoint.reduce((total, val) => total + val) : ''
})
return { id, first_name: data.first_name, point:points };
})
})
}
I tried to put my code in a comment, but I think it's better formated as a answer.
First you need subscribe your pointRef and you can change your code like this.
getCurrentLeaderboard() {
return this.afs.collection('users').snapshotChanges().map(actions => {
return actions.map(a => {
const data = a.payload.doc.data()
const id = a.payload.doc.id;
const pointRef: Observable<any> = this.afs.object(`users/${id}/game`).valueChanges() // <--- Here
const pointsObserver = pointRef.subscribe(points => { //<--- And Here
return { id, first_name: data.first_name, point:points };
})
})
}
....
//Usage:
getCurrentLeaderboard.subscribe(points => this.points = points);
And if you going to use this function alot, you should start to denormalize your data.

Resources