React.js Update component passed as argument - javascript

I'm developing web xmpp chat using React.js and Strophe.js, and I run in quite problem.
XMPP connection is stored single object, but what is tricky, connection status change is handled by class, where i can store the true handler (because displaying connection status will have 2 different views, and Strophe.OnConnection handler cannot be changed after initialization)
What I want to achieve is to pass component to a function, to render itself with new props, something like it
var statusHandler = {
handler:"",
setStatus: function(status) {
React.render(<this.handler value=status/>, dom);
}
}
var firstContainer = React.render(<anotherComponent/>, dom);
statusHandler.handler = firstContainer;
XMPPConnection(login,pwd,statusHandler.setStatus);
//now changing component
var secondContainer = React.render(<anotherComponent/>, dom);
statusHandler.handler = secondContainer;
Or its possible to define callback on component,and pass it as argument (but not a static function)

One idea that may clean up your code would be to emit an event when the connection status changes. Then inside your react components inside componentDidMount listen to that event and set your state accordingly.
Something like this: http://jsfiddle.net/kb3gN/11114/

Related

Use effect wait for Data from previous page

I'm kinda new to the react framework.
As per my requirement , I want to wait until data arrives and binds to my constants in my useEffect() method.
The data is sent encrypted from the main page and is decrypted as follows :
useEffect(() => {
const DecryptedGroupID = atob(groupID.toString());
const DecryptedFactoryID = atob(factoryID.toString());
setProfitAndLossDetails({
...ProfitAndLossDetails,
groupID: DecryptedGroupID,
factoryID: DecryptedFactoryID
});
}, []);
I want to add a waiter/timer/delay to wait until the data gets bound to my const variables. (atob is a decrypting function).
The groupID is required to generate the factoryIDs for the specific group, hence during page reload since it takes time / delay for the hooks to bind, the factoryIDs won't load at times(however when refreshing it appears sometimes), I think adding a delay and giving it time to bind might fix this issue.
Just add groupID and factoryID as your useEffect dependencies. Hook will be called automatically when they are changed. Inside hook you can check if groupID and factoryID not empty, and call your setter function.
Read more about how this hook work:
https://reactjs.org/docs/hooks-reference.html#useeffect
You need to:
Test in the hook if they are defined or not
Call the effect hook when the values you are depending on change (so the hook doesn't run once when they aren't defined and then never run again) — add them to the dependency array.
Such:
useEffect(() => {
if (!groupID || !factoryID) return;
// Otherwise don't return and use them with their values
}, [groupID, factoryID]);

Vuejs watcher order

I have a Vue instance with two watchers:
watch: {
zone:function(zone) {
console.log('Zone watcher');
this.route = {};
},
route:function(route) {
console.log('Route watcher');
if(Object.getOwnPropertyNames(route).length === 0) {
var _this = this;
axios.get(route.url).then(function(response) {
_this.tracks = response.data;
});
} else this.tracks = {};
}
},
When a user selects a zone, route (and tracks) are reset. When user selects a route, tracks are loaded;
I have a component receiving zone and tracks as props, also with two internal watchers that perform some independent actions when any of this props change.
I also have a method that changes both variables:
jump:function(path) {
var parts = path.split(',');
this.zone = this.ZONES[parts[0]];
this.route = this.zone.routes[parts[1]];
},
The problem is watcher for route is fired in first place, then the watcher for zone changes route value triggering its watcher again, reseting tracks value to an empty object.
Is there a way to define the order that watchers must be triggered?
Andrey's comment shows the way. This question comes down to which tools you use for what job. Inevitably there's a bit of opinion... watch is for edge cases. You don't need it often, and if you can do without it, you probably should. watch belongs with computed and v-bind: they're reactive, use them (only) for representing state on screen, you have no (or little) control over when they run, and you shouldn't care.
A server request belongs in a method, or in a function outside of Vue (in your store perhaps) where it can be called explicitly. So create yourself a changeZone() function that clears routes and tracks, then calls the server, then updates your data (or store) with the server response. Your code will be much clearer if these little functional sequences are specified explicitly, in one place. The trigger for your sequence should likely be from an event (user-action) or lifecyle hook, not a watch.

Call componentDidMount when API responds

In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
My problem is in :
ComponentDidUpdate () {
If (this.props.messages.length) {
Const items = this.props.messages.filter (this.isDisplayable);
This.timer = setInterval (() => {
If (items.length> 0) {
This.props.popItem (items);
} Else {
ClearInterval (this.timer);
}
}, This.props.interval);
}
}
In fact it is launched several times and I have warnings of
Warning: flattenChildren (...): Encountered two children with the same
key, 1. Child keys must be unique; When two children share a key,
only the first child will be used.
I used the componentDidMount but it launches it before api responds.
my question is:
Is that there is a way to update the component only at the response of my action, or alternatively to pass the warnings ?
try this :
componentWillReceiveProps(nextProps) {
if (this.props.messages === nextProps.messages) return;
i had some probleme and i resolve it by force update
forceUpdate () {
If (this.props.messages.length) {
...
}
}
In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
None of the methods componentDidMount and componentDidUpdate are good.
Observe the Store in Redux and update your component accordingly when the correct action TYPE is found.
Since you are using the Redux architecture, the state for all your components is in a single place — in the Store.
yes i know, but the problem is that componentDidUpdate is called several times which gives me the index error.
This is quite normal in React. Check this lifecycle.
What you should do is the govern the Redux architecture.
I will try today to provide some diagrams for you.
In general, anything you do will be from the global Store.
You may forget the React.Component state, and props you had in the non-Redux applications.
You typically need to use the Wrapper as a context provider around your app, where the context is the property of React.Component.
The context will be passed to all children and grandchildren so this will be the global Store organization.
Then you will need to read the Store from the context, and call the two typical methods: dispatch and subscribe.

pusher subscription with React-native, setState update

I'm trying to implement function with Pusher-JS in a React-native app but having a difficult time to appropriately update the state of a variable in this app.
Out side of main class, I define
var pusher = new Pusher('xxxxxxxsome number and code');
Inside the main class component, I define a function
test() {
var channel = pusher.subscribe('test_channel');
console.log('ddddddd');
channel.bind('my_event', function(data) {
if (data != null) {
if (data.message != null){
console.log(data.message);
this.setState({
message_box: data.message
});
}
}
}.bind(this));
}
and I put test() under render() function like the below.
render() {
this.what();
...
The app freezes when I push a text message (from pusher testing server) to 'test_channel'(in the mobile app). When I see the log in Chrome console, the console.log('dddddd') and console.log(data.message) keeps being scrolled down very quickly ( seems like test() is re-rendered a lot ).
I tried to take test() outside of render() but I don't know how to separately put and update the state variable outside of main component.
Is there way that I can stabilize this function or way to setState outside of main component ( this )?
Please share any idea with me!
Best
Is your test function being called every time on render? Pusher#bind adds a new callback to its registry whenever it gets called. It could be that whenever a message comes in, this function is being called multiple times, leading to more callbacks in the registry.
Perhaps try binding to an event once, perhaps in getInitialState?

Listening directly to Reflux Actions in Component

From what I've read the pattern is the Components pass data to the Actions which Pass to the Store whose value changes trigger updates in Components that subscribe to the Stores. My question is how to "react" to these triggered updates in the form of a notification? ( ie a successfully saved notification )
Ie do I add logic to the render of this notification component that only displays itself if there is a some flag attribute in the object that its subscribed to? Then deletes itself after a time. This sounds wrong.
UPDATE
Thanks to Hannes Johansson I think I have a better grasp of a pattern. What I have working is the following:
Component passes data through action to the Store
The Store interacts with the api and adds a flag to the model that the component is now notified of an updated model.
createItem: function (item) {
$.ajax({
url: '/items',
method: 'POST',
data: item,
success: function (item) {
CurrentBrandActions.addCampaign(item);
this.item = item;
item.newlyCreated = true;
this.trigger(item);
}.bind(this)
})
}
The Component sees the flag and renders a "Notification Child Component"
var newlyCreated = this.state.item.newlyCreated === true;
if (newlyCreated) {
newlyCreated = <ItemCreatedNotification item={this.state.item} />
} else {
newlyCreated = '';
}
return (
<form onSubmit={this.createItem} className="form">
{newlyCreated}
Something needs to move the app to a new place based on this event. Should this be a) the Notification Child Component b) Parent Component c) The Store?
According to Colin Megill's talk on flux api patterns the api interaction should occur in the Action, but reflux doesn't really allow for that.
UPDATE 2
Component passes data to an Action called createItemRequest
The Action has a preEmit hook that actually does the api call. The createItemRequest continues to the Store so that the store can change the model to reflect the state of sending which is then displayed in the component( maybe show a spinner ). The Action is also responsible for firing two other events depending on the api result.
ItemActions.createItemRequest.preEmit = function (data) {
$.ajax({
url: '/items',
method: 'POST',
data: data,
success: function (item) {
ItemActions.itemCreatedSuccess(item);
},
error: function (error) {
ItemActions.itemCreatedError(error);
}
});
}
There are different approaches to this. For example, in Reflux it's very easy to listen directly to actions if you choose to, since each action is actually a "dispatcher".
However, the general, purist Flux principle is that only stores register with the dispatcher and that components only listen to store updates. And the store just trigger an event that notifies that something has changed, not providing any payload. Then it's up to the component to read the store's state and determine how to render it.
One approach would be the one you describe, put some flag on the items in the store to signal that an update has happened, but it would violate the Flux principle if the components themselves then update the stored items' flags, since only stores are meant to mutate state, and only in response to actions and not from any other source. So in that case the "Flux thing" to do would probably be to trigger yet another event that signals that the newly added item has been noted so that the store can then reset the flag in response to that action.
Another approach I can think of would be to diff the state in your component when it gets notified of a store update. Then keep the flags only in the component, or even keeping newly added items in a separate list in the state and render them separately.
There are no hard rules here, except that if you want to follow the core Flux principle, components should never directly mutate stores' state, because that should only be mutated by the stores themselves in response to actions. That allows for a uni-directional data flow and a single source of truth about the data, which is the main goal of Flux.

Categories

Resources