I want to connect to the coincap.io public socket.io API. I have everything set up but don't know where in my component to put the socket.io code. Does it go in the constructor or componentWillMount or where? It's socket.io so it obviously always needs to be open so where in a component would that go? Here is the code I need to inject somewhere into my component:
this.socket = io.connect('http://socket.coincap.io');
this.socket.on('connect', function(tradeMsg) {
console.log("It worked");
});
Does it go in the constructor or componentWillMount?
Check these answers for details about this:
Can I call APIs in componentWillMount in React?
Why do the React docs recommend doing AJAX in componentDidMount, not componentWillMount?
Where in my component to put the socket.io code?
Use componentDidMount lifecycle method for, it will triggered only once after the component has been mounted successfully, we should write all kind of network calls inside this.
As per DOC:
componentDidMount() is invoked immediately after a component is
mounted. Initialization that requires DOM nodes should go here. If you
need to load data from a remote endpoint, this is a good place to
instantiate the network request. Setting state in this method will
trigger a re-rendering.
Write it like this:
componentDidMount(){
this.socket = io.connect('http://socket.coincap.io');
this.socket.on('connect', function(tradeMsg) {
console.log("It worked");
});
}
You can add socket code into 'componentDidMount`. refer link
componentDidMount(){
this.socket = io.connect('http://socket.coincap.io');
this.socket.on('connect', function(tradeMsg) {
console.log("It worked");
});
}
Related
I'm in bit of a dead-end as I'm not sure how I should go about testing this specific "component". So basically, I have a controller component which is a top-level component. It doesn't take in any props, and it is rendered by a route component. The controller component has several functions, which some are passed into a child component and are triggered by event handlers.
Additionally, the controller component uses an API that is attached to the global window object. The API takes in a callback function which then will be called when you call certain methods on the API, after the methods have been run. Right now, I have no idea how I should try to test the controller. I have tested all child components and verified that everything works, but some of these functions within the controller component would be crucial to test that they actually do work.
const MyController = () => {
const [api, setApi] = useState(null)
useEffect(() => {
const globalApi = window.globalApi
setApi(globalApi)
init()
}, [])
function callBack(e) {
console.log(e)
}
function init() {
api.init(callBack)
}
function close() {
api.close()
}
return (
<MyComponent
close={close}
/>
)
}
Mock your api and see if its called
You can spy on your api call from global (if I read your code correctly). Then you can mock implement it.
const apiCall = jest.spyOn(global.globalApi, 'init').mockImplementation(jest.fn);
expect(apiCall).toHaveBeenCalled();
There's a couple of tests you can do. Check how many times its called, should be once for you. and check what arguments it was called with.
Note
The use of global in the spy. global refers to the window.
Extra tests
Beyond these tests I would suggest making a snap shot of a shallow render, just to make sure the render is always working.
I have an app built in React using hooks that when closed needs to notify the server. I tried doing it using the following approach:
function onUnload() {
if (roomID !== "")
endGame(roomID, dispatch);
}
useEffect(() => {
return onUnload;
},[])
Here, endGame is a function that performs a HTTP request to the backend. But when refreshing the page to emulate a user closing the app, the request never reaches the server, meaning that the cleanup function doesn't get executed. Any ideas on what is wrong?
Thanks in advance
Refreshing the page is not same as component unmount. When you refresh the page, the React state is reset as React solely works on the current client session and refresh is equivalent to resetting it. What you are lloking for might be the onunload event. Try this:
window.onbeforeunload = function(e) {
return onUnload();
};
I know that redux is great for handling the global state of an application, and when that state is updated to reflect that in the view. However, is it possible to use it on a react component that shouldn't re-render? I have a map which uses leaflet and rather than re-render and plot the data, I want it to plot the data without re-rendering.
Does redux seem like a good choice? If so, where would I handle api calls as I was told it should not be done in the reducer.
Currently my app consists of a nav bar, a fullscreen map and a search menu which is populated from an api request. The idea is that when a search is selected it populates data onto the map.
Can you share how you're using Leaflet and React without Redux?
Essentially, React components will always re-render if their state changes, so you can either have a React component that updates on every change, or a Redux-connected component that updates on every subscribed state change. Doesn't make a difference either way.
If you want React/Redux to be 'aware' of your leaflet widget, the only way to do that is to have it re-render on change. Bear in mind that a 'render' function doesn't just throw away and rebuild that part of the DOM, so re-rendering on every change won't cause your leaflet component to be destroyed and rebuilt.
You could connect the Redux dispatcher but not the state, so that you can publish changes to your server through redux, but not have the state connected. This doesn't seem like the ideal approach to use though.
Another approach is to have a 'persistedMapCoordinates' property that is only set when the user confirms their selection, but not on every change. That way the re-render only happens when they lock in their change, not on every small adjustment.
For doing the API calls, you'll want to use redux thunk and middleware. There is tons of info about this available online :)
If your component doesn't re-render, then I'd suggest not complicating it with Redux. It sounds like you just need a component that manages its own rendering.
var MyMapComponent = React.createClass({
componentWillMount: function() {
fetch('/some/data')
.then(this.update);
},
update: function(data) {
// calling setState will trigger shouldComponentUpdate
this.setState({ data: data });
},
loadMap: function(container) {
// calling setState will trigger shouldComponentUpdate
this.setState({
map: L.map(container)
});
},
shouldComponentUpdate: function(nextProps, nextState) {
var map = this.state.map;
var data = this.state.data;
// make updates to map here
// prevent react from re-rendering this component
return false;
},
render: function() {
// pass a reference to the dom node out to loadMap
return (
<div ref={this.loadMap}></div>
);
}
});
Good Morning All!
I've a react Component (a View) that's dependent on a Store which is in turn dependent on having some state pulled from a round-trip to the server.
What I'm looking to understand is if there's a common pattern to solve for initializing the Store's state.
Right now I'm thinking I'd do something like:
var SomeView = React.createClass({
componentWillMount: function() {
SomeStore.addChangeListener(this._onChange);
// Go and tell this thing we want to initiliaze our
// state ahead of time. My worry here is obviously
// that when state is updated this fires again so I'd
// need to have some knowledge that the store has been
// initialized which seems very (very) kludgey
SomeActions.init();
},
render: function() {
// Here i'd want to see if I had items available for
// rendering. If I didn't I'd drop on a loading dialog
// or if I did I could render the detail.
},
_onChange: function() {
// this.setState...
}
});
var SomeActions = {
init: function() {
AppDispatcher.dispatch({
actionType: SomeConstants.INIT
});
}
};
var SomeStore = assign({}, EventEmitter.prototype, {
init: function() {
$.get('/round/trip', function(data) {
this.emitChange();
}).bind(this);
}
emitChange: function() {
this.emit(CHANGE_EVENT);
},
addChangeListener: function(callback) {
this.on(CHANGE_EVENT, callback);
}
});
AppDispatcher.register(function(action) {
switch(action.actionType) {
case SomeConstants.INIT:
SomeStore.init()
break;
default:
}
});
I am absolutely positive there must be a better way.
My worry here is obviously that when state is updated this fires again
componentWillMount fires once component injected to DOM, state updates will not fire this method. However, if you remove component from DOM (for example: not rendering it in parent component based on some condition) and render it later, the method will be fired again. So init will be called multiple times on the store.
I believe you should move http request code to Web API module and fire an action to the API from componentWillMount method, the API will then trigger the store and fire change event on the component, which will update the state and re-render. This is how Flux works.
If you need to get data only once and you know your component is going to be removed from/added to DOM multiple times, you should put a call to the api into upper component in the tree (component that represents an entry point to the widget or something).
I recommend to check Component Container or Higher-order Components pattern, which basically defines a thin wrapper component as a data layer over the view component. Thus you can completely separate your views from data layer and it works good.
You may also want to check another approach, coming from ClojureScript's Om, with a single immutable state. This simplifies everything even more and actually the best way I've found for my self to build apps with React. I've create a starter kit for it, there's a good explanation of main concepts in the readme.
How can I do
after login form submit (React Component)
using flux structure
ajax request that provides response ?
Can you provide some example ?
Basically you need to make an Ajax request, and then create success/error handlers. Inside those handlers, you will create actions to inform your stores of the result. It's probably a good idea to have an AppStore or SessionStore or something that will hold the data related to the current user and the auth token. Your controller-views can listen to that store and render their children when the current user becomes authenticated.
Here's how i made:
When my component bootstraps, I fire an INIT action to the Store which initially gets the datas i need. Here's the simplified data flow
After login my Library component is rendered so i need to initialize the data (books, users etc..)
Library:
componentDidMount: function() {
Store.addChangeListener(this._onChange);
Actions.initialize();
},
As you can see, when my component did mount, i fired a new action, and my store will handle this action.
Store:
switch(action.actionType) {
case Constants.INIT:
_init().done(function() {
Store.emitChange();
});
break;
I'm calling the private function _init() which will return a promise object. When the promise is Fulfilled the Store is ready to emit it's change event.
In _init I'm simulating some async data loads, thats why i made the promise, here it is:
function _init() {
var loadBooksDeferred = new jQuery.Deferred(),
loadUsersDeferred = new jQuery.Deferred(),
loadCategoriesDeferred = new jQuery.Deferred(),
stateReadyDfd = new jQuery.Deferred();
_loadBooks(loadBooksDeferred);
_loadUsers(loadUsersDeferred);
_loadCategories(loadCategoriesDeferred);
jQuery
.when(loadBooksDeferred, loadUsersDeferred, loadCategoriesDeferred)
.then(stateReadyDfd.resolve, stateReadyDfd.reject);
return stateReadyDfd;
}