{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Chrome debug 3000", "type": "chrome", "request": "launch", "url": "https://localhost:3000", "webRoot": "${workspaceRoot}/src" }, { "name": "Debug CRA Tests", "type": "node", "request": "launch", "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/react-scripts", "args": [ "test", "--runInBand", "--no-cache" ], "cwd": "${workspaceRoot}", "protocol": "inspector", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" } ] }
Saturday, 5 January 2019
Debugging Create React App javascript and tests in Visual Studio Code
This is a handy collection of configurations for debugging your Create React App javscript code (launching Chrome) and also tests generated with Create React App (CRA).
Note that the last one does not work probably if you have ejected the CRA. Here is the .vscode/launch.json file:
Etiketter:
Javascript,
NodeJs,
React,
VisualStudioCode,
VsCode
Friday, 28 December 2018
Debugging http Node.js server requests and responses from shell
Here is a cool tip to inspect Node.js running an http process / server.
First off, we start a simple http server in Node.js like this:
const http = require('http'); const server = http.createServer((req, res) => { res.end("This sets up a http server in Node.js. The http module is built-in in Node.js, we only have to require it (import in ES6). Now, just enter the following (I use Windows Subsystem for Linux - WSL in this case) in your shell to export NODE_DEBUG environment variable: export NODE_DEBUG=http We can now see requests and responses in our Node.js server! (Image below uses Wsl-Terminal as our terminal against WSL).Why hello world!
\n"); }); server.listen(4242, () => { console.log("Server is running..."); });
Sunday, 23 December 2018
Canceling Promise in Javascript
Canceling Promise in Js is a often sough after functionality, that can be provided by wrapping the Promise async function and provide canceling abilities. This will in functionality be similar to what we can do
in C# with a CancellationTokenSource using in System.Threading.Task objects. We can invoke asynchronous function in Js with Promise, but if the user navigates away from a View or Page in for example React Native component, clicking a button to go to another Component, we must tidy up already started Promise operations such as fetch and here is the code to achieve that.
First off, we define and export a makeCancelable method to be able to cancel a Promise.
/** * Wraps a promise into a cancelable promise, allowing it to be canceled. Useful in scenarios such as navigating away from a view or page and a fetch is already started. * @param {Promise} promise Promise object to cancel. * @return {Object with wrapped promise and a cancel function} */ export const makeCancelable = (promise) => { let hasCanceled = false; const wrappedPromise = new Promise((resolve, reject) => { promise.then(value => hasCanceled ? reject({ isCanceled: true }) : resolve(value), error => hasCanceled ? reject({ isCanceled: true }) : reject(error) ); }); return { promise: wrappedPromise, cancel() { hasCanceled: true; } }; };The promise is wrapped with additional logic to check a boolean flag in a variable hasCanceled that either rejects the Promise if it is canceled or resolves the Promise (fullfils the async operation). Returned is an object in Js with the Promise itself in a primise attribute and the function cancel() which sets the boolean flag hasCanceled to true, effectively rejecting the Promise and rejecting it. Example usage below:
'use strict'; import React, { Component } from 'react'; import { TextInput, Text, View, StyleSheet, Image, TouchableHighlight, ActivityIndicator, FlatList, AsyncStorage } from 'react-native'; import AuthService from './AuthService'; import { makeCancelable } from './Util'; const styles = StyleSheet.create({ container: { backgroundColor: '#F5FCFF', flex: 1, paddingTop: 40, alignItems: 'center' }, heading: { fontSize: 30, fontWeight: '100', marginTop: 20 }, input: { height: 50, marginTop: 10, padding: 4, margin: 2, alignSelf: 'stretch', fontSize: 18, borderWidth: 1, borderColor: '#48bbec' }, button: { height: 50, backgroundColor: '#48bbec', alignSelf: 'stretch', marginTop: 10, justifyContent: 'center' }, buttonText: { fontSize: 22, color: '#FFF', alignSelf: 'center' }, error: { fontWeight: '300', fontSize: 20, color: 'red', paddingTop: 10 } }); const cancelableSearchRepositoriesPromiseFetch = makeCancelable(fetch('https://api.github.com/search/repositories?q=react')); class LoginForm extends Component { constructor(props) { super(props); this.state = { showProgress: false, username: '', password: '', repos: [], badCredentials: false, unknownError: false, }; } onLoginPressed() { this.setState({ showProgress: true }); var reposFound = []; var authService = new AuthService(); authService.login({ username: this.state.username, password: this.state.password }, (results) => { this.setState(Object.assign({ showProgress: false }, results)); if (this.state.success && this.props.onLogin) { this.props.onLogin(); } }); cancelableSearchRepositoriesPromiseFetch.promise.then((response) => { return response.json(); }) .then((results) => { results.items.forEach(item => { reposFound.push(item); }); this.setState({ repos: reposFound, showProgress: false }); }); } componentWillMount() { this._retrieveLastCredentials(); cancelableSearchRepositoriesPromiseFetch.cancel(); } _retrieveLastCredentials = async () => { var lastusername = await AsyncStorage.getItem("GithubDemo:LastUsername"); var lastpassword = await AsyncStorage.getItem("GithubDemo:LastPassword"); this.setState({ username: lastusername, password: lastpassword }); } _saveLastUsername = async (username) => { if (username != null) { await AsyncStorage.setItem("GithubDemo:LastUsername", username); } } _savePassword = async (password) => { if (password != null) { await AsyncStorage.setItem("GithubDemo:LastPassword", password); } } componentWillUnmount() { } render() { var errorCtrl = <View />; if (!this.state.success && this.state.badCredentials) { errorCtrl = <Text color='#FF0000' style={styles.error}>That username and password combination did not work</Text> } if (!this.state.success && this.state.unknownError) { errorCtrl = <Text color='#FF0000' style={styles.error}>Unexpected error while logging in. Try again later</Text> } return ( <View style={styles.container}> <Image style={{ width: 66, height: 55 }} source={require('./assets/Octocat.png')} /> <Text style={styles.heading}>Github browser</Text> <TextInput value={this.state.username} onChangeText={(text) => { this._saveLastUsername(text); this.setState({ username: text }); }} style={styles.input} placeholder='Github username' /> <TextInput value={this.state.password} textContentType={'password'} multiline={false} secureTextEntry={true} onChangeText={(text) => { this._savePassword(text); this.setState({ password: text }); }} style={styles.input} placeholder='Github password' /> <TouchableHighlight style={styles.button} onPress={this.onLoginPressed.bind(this)}> <Text style={styles.buttonText}>Log in</Text> </TouchableHighlight> {errorCtrl} <ActivityIndicator animating={this.state.showProgress} size={"large"} /> <FlatList keyExtractor={item => item.id} data={this.state.repos} renderItem={({ item }) => <Text>{item.full_name}</Text>} /> </View> ); } } export default LoginForm;
Subscribe to:
Posts (Atom)