I am wondering how I would refactor the following. Basically, after I get the user information from google, it is validated since a specific domain might be allowed. If it passes that one, we validate the token against a back end api.
Sonar is complaining on the use of return displayAlert('LoginFailed') three times. Given the methods have unique use, I am wondering what could be done to improve it?
import React, {useContext} from 'react';
import {View, Alert} from 'react-native';
import {LocalizationContext} from 'library/localization';
import ServiceAuth from 'services/ServiceAuth';
import {saveLoggedInDetails} from 'library/userInformation';
const MyComponent = (props) => {
const {translations} = useContext(LocalizationContext);
const displayAlert = (msg) =>{
//translations happen here
Alert.alert("Failed", msg)
return false;
}
const validateToken = async (userGoogleInfo) => {
const {idToken} = userGoogleInfo;
let serviceAuth = ServiceAuth.getInstance();
try {
return await serviceAuth.validateT(idToken);
} catch (error) {
//show alert here
return displayAlert('LoginFailed')
}
};
const authorize = async (userGoogleInfo) => {
const allowedDomains = [];
let reply = {ok: false};
//check if domain is allowed etc and set to true.
if (!reply['ok']) {
return displayAlert('InvalidDomain');
}
try {
const userInfo = await validateToken(userGoogleInfo);
if (userInfo) {
console.log("okay")
} else {
return displayAlert('LoginFailed')
}
} catch (error) {
return displayAlert('LoginFailed')
}
};
return (
<>
<View>
<Text>Hello</Text>
</View>
</>
);
};
export default MyComponent;
The message is a little bit confusing but sonar is complaining only about the LoginFailed string used three times as parameter.
Create a constant as, for example:
const LOGIN_FAILED = 'LoginFailed';
And then use it in all the three calls to displayAlert:
return displayAlert(LOGIN_FAILED);
Related
I used axios in useEffect of my wrapper component and I sent the data as props to the other component "singleQuestionnaire", in singleQuestionnaire component, I destructured the data, in the first try, it works fine, but after reloading the page it doesn't work with an error : can not read property "map" of undefined
import React, { useEffect, useState } from "react";
import SingleQuestionnaire from "./SingleQuestionnaire";
import { fetchQuestions } from "../../../api/index";
const Questionnaires = ({ match }) => {
const [questions, setQuestions] = useState([]);
const pid = match.params.id;
const getQuestionnaire = async (pid) => {
try {
const { data } = await fetchQuestions(pid);
console.log(data.data, "action in component");
setQuestions(data.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getQuestionnaire(pid);
}, []);
console.log("all questions", questions);
return (
<div>
<SingleQuestionnaire questions={questions} setQuestions={setQuestions} />
</div>
);
};
export default Questionnaires;
and this is my singleQuestionnaire component:
import React, { useEffect, useState } from "react";
const SingleQuestionnaire = ({ questions, setQuestions }) => {
const [questionnaire, setQuestionnaire] = useState([]);
console.log(questions);
const { data } = questions;
console.log("data", data.farmInformationQuestionnaireData);
return <div>simple component</div>;
};
export default SingleQuestionnaire;
For the first time, in console I can see the data "data.data.farmInformationQuestionnaireData". It's an array but for the second time it's undefind.
because questions in SingleQuestionnaire is an empty array before we fetch
which causes an error here
const { data } = questions;
you can add a loading text because initially questions will be an empty array then it will be your res.data (assuming it's an object)
const SingleQuestionnaire = ({ questions, setQuestions }) => {
const [questionnaire, setQuestionnaire] = useState([]);
console.log(questions);
if(questions.length === 0 ) return <h1> Loading</h1>
const { data } = questions;
console.log("data", data.farmInformationQuestionnaireData);
return <div>simple component</div>;
};
it is happening because of the async API call. When you make an async call, the thread does not wait, it moves on and it starts executing other things.
Now your async call might be complete but your callback will not be executed until the stack is empty, that's just how javaScript works. I recommend you use some kind of loader gif or text
{questions ? <SingleQuestionnaire questions={questions} setQuestions={setQuestions} /> : <p>Loading...</p>}
I'm working on a react project where I have created an API and that I want to use for my react project, I'm dealing with react hooks and not able to call API correctly. I have tried couple of things, but I keep getting one or other kind of error.
Latest method I have tried is giving me this error
Line 8:20: React Hook "useFetch" is called in function "filterList" which is neither a React function component or a custom React Hook function
Code for filterList.js look like this
/* to filter the products based on the categories */
import useFetch from './apiService'
export default function filterList(arr, method, courses) {
const URL = "http://localhost:8000/api/getCourses";
const result = useFetch(URL, {});
courses = result;
console.log(courses, 'Inside filterList')
if(method == null) return courses;
else {
return courses.filter(course => {
const categoryArray = course.category.split(" ");
if(arr.length > 0) {
if(categoryArray.some(r => arr.indexOf(r) >= 0)) {
return course;
}
}
else {
return courses;
}
return courses;
})
}
}
and code for apiService.js where I have created useFetch function look like this
import { useEffect, useState } from 'react';
// to fetch the data from api
const useFetch = (url, defaultData) => {
const [data, updateData] = useState(defaultData);
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const json = await response.json();
updateData(json);
}
fetchData();
}, [url]);
return data;
};
export default useFetch;
Please let me know what is the thing that I'm doing wrong and what should be correct method to do this.
I'm trying to store persistent data for an an electron app with electron-json-storage, I tried using neDB but it would throw this error so I switched however it looks like it's not neDB's issue but my own.
Here is the problem: I'm trying to get information out of the storage and when I call the respective get method and put the information out to the console everything seems fine inside the Getmethod, everything even seems fine when i do console.log(Get()) but as soon as I try to map it or get the length of the returned array it thinks that array is empty.
Here is my code:
import * as React from "react";
import { Component } from "react";
import { ToastContainer } from "react-toastify";
import { connect } from "react-redux";
import GetAllCharacters from "../../scripts/GetAllCharacters";
const mapStateToProps = (state) => {
return {
character: state,
};
};
const mapDispatchToProps = (dispatch) => ({});
const Sheet = (props) => {
const [characters, setCharacters] = React.useState();
return (
<div className="container-fluid">
<div className="row" style={{ marginRight: "0px" }}>
{props.character != null ? (
<>
//Code Removed for irrelevancy
</>
) : (
<>
{console.log(GetAllCharacters()}<--prints an array of characters to the console
{GetAllCharacters().length}</><--returns 0 despite the fact it just printed the characters to the console
)}
</div>
</div>
);
};
export default connect(mapStateToProps, mapDispatchToProps)(Sheet);
GetAllCharacters()
import { Character } from "../Data/Character";
function GetAllCharacters() {
var returnCharacters: Character[] = [];
const storage = require("electron-json-storage");
storage.getAll(function (error, data) {
if (error) throw error;
Object.entries(data).map((c) => {
returnCharacters.push(<Character>c[1]);
});
});
console.log(returnCharacters);
return returnCharacters;
}
export default GetAllCharacters;
GetAllCharacters should be an async function (since it fetch some async datas). GetAllCharacters().length will always be 0 since GetAllCharacters() returns an empty array.
function GetAllCharacters() {
var returnCharacters: Character[] = [];
const storage = require("electron-json-storage");
// ** HERE IS THE PROBLEM ** This is async. and the next line will get runned instantly and donesn't wait for it to get the data.
storage.getAll(function (error, data) {
if (error) throw error;
Object.entries(data).map((c) => {
returnCharacters.push(<Character>c[1]);
});
});
// ** Now returnCharacters is empty array, and it will return it.
console.log(returnCharacters);
return returnCharacters;
}
you should correct your GetAllCharacters function to get all the results asyncronously and at the end return the result array (with callback for example). and then you should call GetAllCharacters(result => {setCharacters(result)}) in your component with useEffect for example, and then bind the characters to render.
Could someone please explain what is going wrong in simple terms so I know how to fix this and can deal with it next time I encounter it.
I have looked through all related questions I could find on stackoverflow and haven't been able to fix it, if I have missed one that answers this then please link it.
I have had this error in the past but usually that was just because I had a typo (e.g. a capital instead of a lowercase) or did not import something correctly however that is not the case this time as far as I can tell.
FIRST CODE app.js
SECOND CODE interactions.js
Here is my code
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Navbar from './Navbar'
import Web3 from 'web3';
import { connect } from 'react-redux'
// import Token from '../abis/Token.json'
import {
loadWeb3,
loadAccount,
loadToken,
loadExchange
} from '../store/interactions'
class App extends Component {
componentWillMount() {
this.loadBlockchainData(this.props.dispatch)
}
async loadBlockchainData(dispatch) {
const web3 = loadWeb3(dispatch)
const network = await web3.eth.net.getNetworkType()
const networkId = await web3.eth.net.getId()
const accounts = await loadAccount(web3, dispatch) // <<--
const token = loadToken(web3, networkId, dispatch)
loadExchange(web3, networkId, dispatch)
}
// ......................
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
export default connect(mapStateToProps)(App);
import Web3 from 'web3'
import {
web3Loaded,
web3AccountLoaded,
tokenLoaded,
exchangeLoaded
} from './actions'
import Token from '../abis/Token.json'
import Exchange from '../abis/Exchange.json'
export const loadWeb3 = (dispatch) => {
const web3 = new Web3(Web3.givenProvider || 'http://localhost:7545')
dispatch(web3Loaded(web3))
return web3
}
export const loadAccount = async (web3, dispatch) => {
const accounts = await web3.eth.getAccounts()
const account = accounts[0]
dispatch(web3AccountLoaded(account))
return account
}
export const loadToken = async (web3, networkId, dispatch) => {
try {
const token = new web3.eth.Contract(Token.abi, Token.networks[networkId].address) // new 이거 의존성(버전) 문제 이거 조심!!!!!
dispatch(tokenLoaded(token))
return token
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
export const loadExchange = async (web3, networkId, dispatch) => {
try {
const exchange = new web3.eth.Contract(Exchange.abi, Exchange.networks[networkId].address)
dispatch(exchangeLoaded(exchange))
return exchange
} catch (error) {
window.alert('Contract not deployed to the current network. Please select another network with Metamask.')
return null
}
}
i don'k now why this happening to me
but please let me know this problem if you know this issue
The problem seems to be that you do not define or import the accountSelector function anywhere.
You usually define Redux selector functions in your reducer definition files: they take the current Redux store state as argument (and optionally the connected component props) and return the value to be used in your MapStateToProps object property.
Ex.
export const accountSelector = (state) => state.account
You can read more about selectors on the dedicated Redux resources page
replace this
function mapStateToProps(state) {
return {
account: accountSelector(state)
}
}
with this
function mapStateToProps(state) {
return {
account: state.accountSelector
}
}
you are passing complete state in variable instead of accessing.
for your reference, how to access please go through official documentation for your better understanding Redux
I am making auth component using react-native.
And the code below sends to 'MainTab' of 'this.props.navigation' depends on the result of axios.
<TouchableOpacity onPress={this.handleSubmit}>
<Text>Save</Text>
</TouchableOpacity>
handleSubmit = () => {
const result = await axios.post(
'http://192.0.0.1:4000/clients',
users
);
if (result.data.success) {
return this.props.navigation.navigate('MainTab');
}
return false
};
But I want to use handleSubmit at an other 'js' file to avoid doing repeatedly.
Thus, I edit a code like below.
import { saveSettings } from '../../storage/settingsStorage'
handleSubmit(): void {
saveSettings(this.state);
}
// in 'settingsStorage.js'
export const saveSettings = async users => {
try {
const result = await axios.post(
'http://192.0.0.1:4000/clients/token',
users
);
if (result.data.success) {
return this.props.navigation.navigate('MainTab');
}
return false
} catch (e) {
console.log(e);
}
};
And in this case, I know 'this.props' can't be passed in normal Js file without passing props. But I don't know how can I pass the props?
Thank you so much for reading this.
Based on your description I think you can just add a second parameter to saveSettings and pass the navigation object through:
import { saveSettings } from '../../storage/settingsStorage'
handleSubmit(): void {
saveSettings(this.state, this.props.navigation);
}
// in 'settingsStorage.js'
export const saveSettings = async (users, navigation) => {
try {
const result = await axios.post(
'http://192.0.0.1:4000/clients/token',
users
);
if (result.data.success) {
return navigation.navigate('MainTab');
}
return false
} catch (e) {
console.log(e);
}
};
Instead of passing navigation prop you can use a technique Navigating without the navigation prop as described in official site .
App.js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import NavigationService from './NavigationService';
const TopLevelNavigator = createStackNavigator({
/* ... */
});
const AppContainer = createAppContainer(TopLevelNavigator);
export default class App extends React.Component {
// ...
render() {
return (
<AppContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
);
}
}
we define NavigationService which is a simple module with functions that dispatch user-defined navigation actions.
/ NavigationService.js
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
Now use it every where without navigation prop
// any js module
import NavigationService from 'path-to-NavigationService.js';
// ...
NavigationService.navigate('MainTab');