I am new to Redux and I have encountered this issue and cannot seem to find a solution for it.
I have several API calls inside of thunks and they all work fine. This one however fails. It is different to the others in the sense that I am implementing a search feature that uses payload. I have tried to debug it but can't seem to find where the error happens exactly.
this is the error that I get on the screen:
these are the action, reducer and code in the search component:
and this is the logic to connect the component to the store and access state and actions:
Surely it must be something I am not fully understanding, I hope you can make some sense out of this.
You should change action.loadSearchResults.result to action.searchResults.result. I am assuming there is a key called result you are getting in your response from HomePageApi.searchResults(searchInput).
I know this because in your action you have this code:
export function searchMoviewResultsSuccess(searchResults) {
return {
type: types.SEARCH_RESULTS_SUCCESS,
searchResults: searchResults // This is the key you should get in your reducer not `loadSearchResults`
}
}
Related
I want to add a Listener beforeRemove to a navigation to prevent the user from going back.
Then they get an alert to proceed or discard.
I followed the tutorial from reactnaviagtion.org but this is in an functional Component.
In my Case its an react-native Class-Component.
I can easily call the function over the props:
componentDidMount(){
this.props.navigation.addListener("beforeRemove", (e) =>{
console.log("beforeRemoveTriggered");
this.state.SomeVariablesToCheckIfGameStarted
Alert.alert(..., onPress: ()=> this.props.navigation.dispatch(e.data.action));
}
}
The console.log is no problem but I can't call the state inside of the callback.
beforeRemoveTriggered
But after that I get the following error:
TypeError: undefined is not an object (evaluating '_this2.props.someVariablesToCheckIfGameStarted`)
- node_modules\...
My Guess is that you cant call the state inside of the listener-callback.
But this is neccessary for the app function so i cant "just dont use the state".
BTW a workaround with useEffect would be accetable but is not preferred.
This may have a simple solution which is not specific with react-navigation or react-native but javascript.
Any tips would be helpful, thanks in advance!!!
I know my answer...
Maybe but just maybe I called this.props instead of this.state
And maybe after this discovery everything works as it should be...
I`m sorry to everyone I bothered figuring out what the solution is!
I have a react-redux application, and I catch every error response from redux-saga, save it in the redux-store and render it in the component. The main problem is the ability to remove it when the component is updated or when the user has moved to another page. I tried to use the component lifecycle methods (componentWillUpdate), but it didn’t work correctly because I had other store parts connected to the component, and when they are updated, it clears the error before the user sees it.
My question is: is there a proper way to store/view/delete errors using the redux?
I handle errors in this way
export function* errorHandler(err: any): SagaIterator {
// put an error in the redux-store
}
// it's a wrapper for every saga
export const genericErrorHandler = (saga: (...args: any[]) => SagaIterator, ...args: any[]) =>
function* handleApp(action: any): any {
try {
yield call(saga, action, args);
} catch (err) {
yield call(errorHandler, err);
}
};
I could probably give a more specific suggestion if we had more details about the design of your app & how you're handling errors. But here are some things that might help:
split up errors by type, with separate actions/reducers/store locations for each. This will help you be specific about what kind of error has occurred and when/how to show each.
fire an action to clear the error state. This ensures you're being specific about what errors are no longer present, and when that change occurs. If possible, don't do this as a side effect of something else happening, be specific about when & why.
if the error state is specific to a UI component, and should be removed from the store when that component goes away, consider firing the error-clearing action in that component's componentWillUnmount method. This is called only when the component is being removed from the DOM.
I have been working with Redux & React for a few months. I usually always use Chrome with no issues. ( Endless bugs actually :) ).
When I started testing in Firefox I ran into an issue which I need some help with ... To know if there is a perfect way at dealing with this ...
Issue
Redux Props for MapStateToProps are not yet available when the constructor gets called, which means I cannot construct my components state in the component constructor. These props become available swiftly afterwards in the render function. At this stage, it is too late because I cannot construct state in the render function (Could somehow work that, but wouldn't be good to approach right ?).
For the moment I am using the componentWillReceiveProps and duplicating my constructor function with one exception
Constructor function
constructor(props){
super(props);
//Loads of code named A
this.state = {state:A};
}
Component Will Receive Props Function
componentWillReceiveProps (){
//Loads of code named A
this.setState({state:A});
}
There may be an issue over overwriting my state here, but for my exact case here, its only displaying data, no UI changes happen... This doesn't appear correct method either way...
I read this article
https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
I am not quite sure if I understand this fully. I did experiment with it a little with no working solutions.
Ideally, I need the constructor to pause until all redux store is populated which also doesn't make sense. Props arrays could be empty.
There are discussions on Slack but none seem to address this exactly. I tried googling issue but couldn't find exact issue addressed ...
I need the mapStateToProps props to construct my state. It is looking like I won't be able to do this and will need to totally refactor code to work more solely in the render function with loads of ternary operators and/or making calls to set state from the render function before the render returns.
Any thoughts on this issue?
Daniel
Why do you think you need put the data you get from props into the component state?
As far as using the data there is no difference between the two except that you're more likely to get into trouble if you copy props to state (see link you posted).
const { A } = this.state;
const { A } = this.props;
If the data is coming via an async method then you should accommodate that in your render method.
render() {
const { A } = this.props;
if (!A) {
return <LoadingIndicator />
}
...
}
I'm still pretty new on React development, but I've already work on 3 big project using React+Redux and I see a pattern that I dislike a lot:
componentWillReceiveProps(nextProps) {
if (nextProps.params.type === TYPE_NEW_USER) {
this.modalUsername = this.props.showPopup( < NewUsernamePopup onClose = {::this.closeUsernamePopup
}
/>, USERNAME_POPUP_ID, true);
}
if (this.state.kind !== nextProps.kind || this.state.filter !== nextProps.filter || this.state.hashtags !== nextProps.hashtags) {
this.setState({
results: [],
loading: true,
kind: nextProps.kind,
filter: nextProps.filter,
hashtags: nextProps.hashtags
}, () => this.manageResults(nextProps.results, false));
} else {
this.manageResults(nextProps.results, true);
}
this.managePages(nextProps.paging);
}
I would like to avoid the ifs inside the componentWillReceiveProps. How do you handle it? We've analysed another project using Flux and callback registration. It looks like:
componentWillMount() {
EntityStore.on(EntityActions.ENTITIES_LOADED, this.getData.bind(this));
EntityActions.entitiesLoaded();
}
The first event is emitted by the component, but afterwards the store emits the event and the component updates. Additionally a single store keeps its state and do not duplicate async calls if it already has the content. I personally like to avoid the ifs, but I do NOT want to lose Redux (its community and tools).
How would you add the current logic (ifs) inside the componentWillReceiveProps outside the component? I would like to handle the logic in a service layer and not inside the component.
I would definitely appreciate to read your opinion around this, because I've been struggling to find a solutions that fits.
The redux approach is to put the logic into the actions/reducers.
So i don't know what your manageResults method does, but it is probably the piece of logic you want to move into a reducer so you won't need to call it from your component anymore.
So the kind,filter and hashtagsvariables should be updated from redux actions only.
tl;dr properly following redux best practices would eliminate some of these conditions, but I'd be more concerned about the overall design this snippet is revealing.
To address the individual lines:
if (nextProps.params.type === TYPE_NEW_USER) {
This looks like a redux action was passed to the component? If so, that's not great, only the reducers should care about action types.
this.modalUsername = this.props.showPopup(
The lifecycle hook componentWillReceiveProps is not the right place to initiate things like that, the resulting React component in an instance var also looks quite weird.
if (this.state.kind !== nextProps.kind || this.state.filter (etc.) ) {
If you have UI state in this component that is somehow dependant on the props coming from redux, these types of ifs are somewhat necessary, since you can't do it outside the component.
You are right to dislike this "pattern", which seems to reflect bad overall design. This component seems to be involved with "pages", "results", a username, and some ajax fetching with a loading flag. Can only speculate of course, but it seems like it's doing too much. The ajax request lifecycle should definitely be modelled in a reducer.
That said, the lifecycle hooks do often contain a bunch of ifs, since the reducers don't see routing and which components get mounted/unmounted, so that's where you have to react to changing props sometimes.
mapStateToProps returns an object with 2 keys, provider & plan.
The provider's value cannot be resolved until the plan is already a property of props. provider depends on the plan's property (plan.provider).
My idea was, the first time mapStateToProps gets invoked, it will return the following:
(And that is indeed what happens)
{
plan: [Object],
provider: undefined
}
Now that the plan is resolved and mapped to props I need the mapStateToProps to get invoked once again so that the provider can resolve aswell. The second time mapStateToProps should return:
{
plan: [Object],
provider: [Object]
}
Is this the right way to deal with a situation like this?
I dont think this is a good way to solve this. I believe if you have plan as a promise or an async action that you have to wait for before updating provider value, you need to do it Redux Middleware.Most reliable of them in my opinion is Thunk, which allows you to write async code in actions and then when the Promise resolves, you can update provider in your state.
To avoid undefined provider value at the UI, use defaultProps which will help you to avoid issues because of undefined provider.
I hope that helps.
Yes, that's a perfectly reasonable approach. Assuming that a second action is dispatched which adds the appropriate data to the store, mapState will re-run and return the updated values, and the component will re-render.
Your React component should be written so that it can safely handle the missing provider prop, such as checking to see if it exists and returning a "loading..." component if it doesn't.