I am using react-native and react-redux to create a simple app. Thus, all of my props are passed in from mapStateToProps, coming from redux.
I should have to use mapDispachToProps to manipulate the props but that is not what is happening.
I have an event handler that allows me to directly manipulate the props. Why is this behavior occurring?
nameHandler(text) {
console.log(this.props.group.name); //output: Billy
this.props.group.name = 'illegal!';
console.log(this.props.group.name); // output: illegal!
}
I am binding 'this' to 'nameHandler' within the constructor, but that doesn't seem relevant.
I've mostly gotten around this, but shouldn't this not be possible?
Related
I have a quite decent background in android but now I am starting digging into react native and I am really confused with the ways to change the state of a component through hooks and set state function.
To the point, I have my main screen and I have many small components which change visibility. This is done by letting the user change some filter settings within dialogs. So the suggested way to do that is by having a hook in my main screen with a list that holds the values for the visibility of each component. But since I change the visibility of the components from inside the modals, every time I want to show a modal I will have to pass in a different function(for example setComponentEnable or setComponentDisabled) to set the state for each component. So my main screen will be polluted from all these small functions. Also I should not forget to mention that my modals are consisted from many smaller components and I will have to pass as deep as it goes the proper function to match the user action.
So my question is, is there a way to do this thing without polluting my main with all these small functions and make it possible for the main screen to update every time the user change the filters within the modals?
I already read about context but the docs say:
Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
So I dont think that this should be a great case for context use.
What I am trying to do now is create a hook with a list
const [isibility, setVisibility] = useState([]);
create visibility handler functions
const setVisibilityEnable = () => {
...
}
and pass it into my modal.
<MyModal
visibilityHandler={setVisibilityEnable}/>
Is there a way to manipulate the state without passing all these callbacks to the modals? Or maybe is there anyone that can suggest a better and clean solution to avoid end up having a really huge main screen?
you can include all the settings in one object and pass that object to all the components. Then each component will then modify that object accordingly.
const defaultVisibility = {
childComponentOne: true,
childComponentTwo: true,
};
const [visibilityObject, setVisibilityObject] = useState(defaultVisibility);
pass both the function and the object into your child components:
<ChildComponentOne visibilityObject={visibilityObject} setVisibilityObject={setVisibilityObject} />
Then in your child component, you set the visibility like so:
setVisibilityObject({...visibilityObject, childComponentOne: false});
Why you don't just pass a property to your modal and check if changed in oncomponentdidchange method?
componentDidUpdate(prevProps) {
if (this.props.yourPoperty!== prevProps.yourPoperty) {
//do your visibility stuff
}
}
Alternatively you can do it with redux when you connect your components to the store.
I'm trying to understand the solution in this SO post. The solution allows the user to keep track of the previous route in the current route.
Below is the snippet of Vue code that I'm trying to understand. If I understand correctly, next accepts a callback function that receives the current component's vue instance. We then set the prevRoute data property of this vue instance to from. Is this interpretation correct? If not, what is actually happening?
If someone could also add a brief explanation as to what the Vue API is doing behind the scenes that would also be very helpful for me to actually understand the snippet of code.
...
data() {
return {
...
prevRoute: null
}
},
beforeRouteEnter(to, from, next) {
next(vm => {
vm.prevRoute = from
})
},
...
As per the documentation...
The beforeRouteEnter guard does NOT have access to this, because the guard is called before the navigation is confirmed, thus the new entering component has not even been created yet.
However, you can access the instance by passing a callback to next. The callback will be called when the navigation is confirmed, and the component instance will be passed to the callback as the argument
So vm is the component instance assigned to the destination route.
From your question...
We then set the prevRoute data property of this vue instance to from. Is this interpretation correct?
Almost. All you're doing is setting a direct object property on the Vue component which is after all, just a JavaScript object at heart. For example
const vm = { name: 'I am totally a Vue component' }
vm.prevRoute = from
This property will not be reactive but you can certainly access it within your component via this, just as you can other non-data properties like $el, $refs, etc.
I'm working on an app in React Native, and am having trouble accessing props that I feed into a component I made.
If I do console.log(this.props) within the constructor, I can see the props display in the console as desired, however if I put it in any other method, it prints undefined. How can I access the props that are clearly being sent to the component from outside of the constructor method?
You are probably adding new methods that are not binding this.
Check if you are writing the method like this:
myMethod(){
//Code
}
and just change it to:
myMethod = () => {
//Code
}
Edit: Like #Li357 says, these are called arrow functions. Arrow functions don't bind this automatically, and as a consequence receive the this of the surrounding class. In your case it will solve your issue as you want to access the properties of that class but you might want to read about it and how binding works in JS classes.
Another option is to write function.bind() but either way should work.
EDIT AGAIN: Opened an issue with Reflux here: https://github.com/reflux/refluxjs/issues/544
EDIT: Reflux setState does not provide any callback for setState. They require you to use the component lifecycle methods to ensure the state is set prior to running any code. If you ever need to use the reflux setState outside of a component, where you do not have lifecycle methods, you will not be guaranteed the state is set. This is due to how Reflux does their setState. It loops all listening components and calls those components' setState methods. If Reflux were refactored to wait until all the listening components' setState calls complete then call a callback passed into its own setState method, that may work, but it would likely require a large rework of Reflux. I have started using a singleton class to manage some of these variables, as they are fully outside the component lifecycle.
Can you use setState with a callback in ReactNative or is that only in React? I'm using the below syntax and the first debugger is hit, but the second debugger and console log never get hit.
EDIT: After digging some more, it seems this does not occur when using setting the state directly, but only when running it through a reflux store and/or not using a component.
See snack here: https://snack.expo.io/S1dm3eFoM
debugger
this.setState(
params,
() => {
debugger
console.log("CALLIN IT BACK")
}
)
I'm the creator of Reflux's ES6 styled stores/component hookups. Hopefully I can shed some light on this for you.
Here's the important points:
1) Reflux sets its store state immediately upon setState calls.
Reflux's store state doesn't have the same problems as React and doesn't need React's workaround (callback). You are guaranteed that your change is immediately reflected in the store's state, that's why there is not a callback. The very next line of code will reflect the store's new state.
tl;dr, no workaround is required.
// in Reflux stores this works
this.setState({foo:'foo'});
console.log(this.state.foo === 'foo') // true
this.setState({foo:'bar'});
console.log(this.state.foo === 'bar') // true
2) Stores can never depend upon components!
The idea that the setState would give a callback about when the dependent components have all updated their state is a major violation of the single most fundamental of all flux principles: 1 way data flow.
If your store requires knowledge about whether or not components are doing something then you are already doing it wrong, and all the problems you are experiencing are XY problems of fundamentally not following flux in the first place. 1-way data flow is a main flux principle.
And that principle exists for good reason. Flux doesn't require 1:1 mapping of store state properties to component state properties. You can map anything to anything, or even just use the store's state for the building blocks of how you will run your own logic to create completely new state properties on the components. For example having loaded and transitioned as separate properties in store state, but mapping to a loadedAndTransitioned property in one component, and a notLoadedOrTransitioned in another component via your own custom logic. That's a hugely powerful part of flux. But your suggestion would pretty much destroy all that, since Reflux can't map people's custom logic.
1-way data flow must be maintained; Store's must operate the same independently of what components utilize them. Without this, the power of flux falls apart!
Store's listen to actions, components listen to stores, actions are called from wherever. All flux-based data flows from action -> store -> component only.
I've checked the library for the refluxjs and the problem and the workaround are as mentioned below.
Problem
The library provides with a new instance of the setState which is not exactly similar to ReactJS setState, which omits the callback as mentioned in their code below.
/dist/reflux.js
proto.setState = function (obj) {
// Object.assign(this.state, obj); // later turn this to Object.assign and remove loop once support is good enough
for (var key in obj) {
this.state[key] = obj[key];
}
// if there's an id (i.e. it's being tracked by the global state) then make sure to update the global state
if (this.id) {
Reflux.GlobalState[this.id] = this.state;
}
// trigger, because any component it's attached to is listening and will merge the store state into its own on a store trigger
this.trigger(obj);
};
Also as mentioned here in the docs
That store will store its state on a this.state property, and mutate its state via this.setState() in a way that is extremely similar to React classes themselves.
WorkAround
The library provides with the listener functions, which provide us with the callbacks of the setState obj of the ReactJS as mentioned in the below snippet.
/dist/reflux.js
componentDidMount: function() {
var me = this;
_.extend(me, ListenerMethods);
this.listenTo(listenable, function(v) {
me.setState(_.object([key],[v]));
});
},
You can use them in the following way
this.listenTo(action, callback)
Hope it clears the doubts
Edit:
Usage as per the docs
To listen inside of the store
constructor()
{
super();
this.state = {count: 0};
this.listenTo(increment, this.incrementItUp);
}
incrementItUp()
{
var newCount = this.state.count + 1;
this.setState({count: newCount});
}
To listen outside of the store anywhere
// listen directly to an action
myActions.actionName.listen(myCallbackFunc);
// listen to a child action
myActions.load.completed.listen(myCallbackFunc);
Here's the link to the snack with working callbacks based on Promises
I am using react native.
Here's my code.
function mapStateToProps(state) {
return {
markers: state.markers,
};
}
I set props using mapStateToProps and it only called when I dispatch an action.
I can set state using setState({..}); like this.
Here's my question.
How can I set props? Is there anything like setProps({..})?
It seems like you're using Redux. If you do, make sure to have both reducer and action scripts. The reducer is used to get a value from a specific state property or properties.
You have to define a function in your action script to assign or set a value to your specific state property and properties. You also need a store to bring both reducers and actions together.
The store initializes everything and allows you to dispatch actions and set or get values.
Two common ways of passing the props.
From Redux Store
Like what you have done in your code.
From other Components
Props can be passed by
<Foo prop1={bar} />
And in your Foo Component the props of prop1 is whatever bar is.