Rewrite condition to use only one console.log - javascript

movies = [1,2,3,4,5];
watchedMovies = [1,2,3];
const buttonPressed= false;
movies.map(item => buttonPressed === true ? !watchedMovies.includes(item) &&
console.log(item) : console.log(item))
How can I rethink this to use only one "console.log". I have a button in my react app that if I press will hide my watched movies and the "console.log" is actually a "JSX" element with all the logic here so will be hard for me to transform it into a component so I don't reuse code.

Based on your own answer, I think what you actually want is a filter:
let visibleMovies = movies;
if (!buttonPressed) {
visibleMovies = visibleMovies.filter(item => !watchedMovies.includes(item))
}
// ...
visibleMovies.map(item => /*make JSX element*/)

movies.map(item => (buttonPressed === true || !watchedMovies.includes(item)) &&
console.log(item))

Related

React - CheckboxTree filter

So i am using this package "react-checkbox-tree" to make a checkbox, but since this is made on classes components and i need to do it with functions and hooks, this is being a bit tricky to my actual skills.
//Checkbox Tree
const [checkedTree, setCheckedTree] = useState([]);
const [expandedTree, setExpandedTree] = useState(["1"]);
const [filterText, setFilterText] = useState("");
const [nodesFiltered, setNodesFiltered] = useState();
///FILTER LOGIC /////
const onFilterChange = (e) => {
setFilterText(e.target.value);
if (e.target.value) {
filterTree();
}
};
const filterTree = () => {
// Reset nodes back to unfiltered state
if (!filterText || filterText === "" || filterText.length === 0) {
setNodesFiltered(nodes);
return;
}
const nodesFiltered = (nodes) => {
return nodes.reduce(filterNodes, []);
};
setNodesFiltered(nodesFiltered);
};
const filterNodes = (filtered, node) => {
const children = (node.children || []).reduce(filterNodes, []);
if (
// Node's label matches the search string
node.label.toLocaleLowerCase().indexOf(filterText.toLocaleLowerCase()) >
-1 ||
// Or a children has a matching node
children.length
) {
filtered.push({ ...node, ...(children.length && { children }) });
}
return filtered;
};
//
My first problem is that when i search for the parent, i only get the last children of the array for some reason.
The Second is that when i use the backspace button, the filter stops working until i clean every char.
I made a codesandbox to help you guys to understand the problems:
https://codesandbox.io/s/checkboxtree-6gu60
This is the example on with classes:
https://github.com/jakezatecky/react-checkbox-tree/blob/master/examples/src/js/FilterExample.js
Tks in advance!
For your second problem, I solved it by passing through onKeyDown as well as onChange from my search input:
<input
type="text"
onChange={onFilterChange}
onKeyDown={onBackspace}
/>
which calls
// If the user deletes the search terms, reset to unfiltered
const onBackspace = e => {
var key = e.keyCode || e.charCode
// magic numbers are backspace and delete. Naming them didn't work.
if (key == 8 || key == 46) {
setFilterText("")
filterTree()
}
}

Array item toggling simplification in pure javascript

is it possible to simplify the following code further, or is this the cleanest way possible? What I'm trying to do is, if the action.payload is not included in roles array, push it into it, if it is there remove it. I don't want to use lodash for this.
const idx = state.rolesFilter.findIndex(
role => role === action.payload,
);
if (idx === -1) {
nextState.roles.push(action.payload);
} else {
nextState.roles = state.roles.filter(role => role !== action.payload);
}
You could use Set
const set = new Set(state.roles);
const action = set.has(action.payload) ? 'delete' : 'add';
set[action](action.payload);
nextState.roles = [...set];
If you plan on using "toggle" a lot you may create a function
function toggle(array, item) {
const set = new Set(array);
const action = set.has(item) ? 'delete' : 'add';
set[action](item);
return [...set];
}

How to break the for loop using state

I have code as below.
I need to break the loop when first match is found.
const [isCodeValid, setIsCodeValid] = useState(false);
for (let i = 0; i < properyIds.length; i++) {
if (isCodeValid) {
break; // this breaks it but had to click twice so state would update
}
if (!isCodeValid) {
firestore().collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies').get()
.then(companies => {
companies.forEach(company => {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
console.log("should break here")
// updating state like this wont take effect right away
// it shows true on second time click. so user need to click twice right now.
setIsCodeValid(true);
}
});
})
}
}
state won't update right away so if (!isCodeValid) only works on second click.
Once I find match I need to update state or variable so I can break the for loop.
I tried to use a variable but its value also not changing in final if condition, I wonder what is the reason? can anyone please explain ?
You should try and rewrite your code such that you will always call setIsCodeValid(value) once. In your case it could be called multiple times and it might not get called at all
const [isCodeValid, setIsCodeValid] = useState(false);
function checkForValidCode() {
// map to an array of promises for companies[]
const companiesPromises = properyIds.map(propertyId =>
firestore()
.collection(`properties`)
.doc(propertyId)
.collection('companies').get())
Promise.all(companiesPromises)
// flatten the 2d array to single array, re-create to JS array because of firestores internal types?
.then(companiesArray => [...companiesArray].flatMap(v => v))
// go through all companies to find a match
.then(companies =>
companies.find(
company => _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
))
.then(foundCompany => {
// code is valid if we found a matching company
setIsCodeValue(foundCompany !== undefined)
})
}
Try something like this:
import { useState } from 'react';
function YourComponent({ properyIds }) {
const [isCodeValid, setIsCodeValid] = useState(false);
async function handleSignupClick() {
if (isCodeValid) {
return;
}
for (let i = 0; i < properyIds.length; i++) {
const companies = await firestore()
.collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies')
.get();
for (const company of companies.docs) {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
setIsCodeValid(true);
return;
}
}
}
}
return (<button onClick={handleSignupClick}>Sign Up</button>);
}
If you await these checks, that will allow you to sequentially loop and break out with a simple return, something you can't do inside of a callback. Note that if this is doing database queries, you should probably show waiting feedback while this is taking place so the user knows that clicking did something.
Update:
You may want to do all these checks in parallel if feasible so the user doesn't have to wait. Depends on your situation. Here's how you'd do that.
async function handleSignupClick() {
if (isCodeValid) {
return;
}
const allCompanies = await Promise.all(
properyIds.map(id => firestore()
.collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies')
.get()
)
);
setIsCodeValid(
allCompanies.some(companiesSnapshot =>
companiesSnapshot.docs.some(company =>
_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
)
)
);
}
Can you not break it after setIsCodeValid(true);?
Use some:
companies.some(company => {
return _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase());
});
If some and forEach are not available then companies is not an array but an array-like object. To iterate through those, we can use for of loop:
for (const company of companies){
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
// do something
break;
}
}
I tired below and it worked for me to break the loop.
I declared and tried to change this variable let codeValid and it was just not updating its value when match found. (not sure why)
But all of a sudden I tried and it just works.
I didnt change any actual code except for variable.
let codeValid = false;
let userInformation = []
for (let i = 0; i < properties.length; i++) {
console.log("called")
const companies = await firestore().collection(`properties`)
.doc(`${properties[i].id}`)
.collection('companies').get()
.then(companies => {
companies.forEach(company => {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
// a += 1;
codeValid = true;
userInformation.registrationCode = registrationCode.toUpperCase();
userInformation.companyName = company.data().companyName;
userInformation.propertyName = properties[i].propertyName;
}
});
})
if (codeValid) {
break;
}
}

Writing if/else statements with 3 conditions with a promise mixed in

So I have this conditional statement with 2 conditions, whereby
let modItemList = this.props.items
if (this.state.searchItemName) { // condition1
modItemList = (
this.props.items.filter(
(item) => item.name.toLowerCase().indexOf(lcName) !== -1 // For name
)
);
} else if (this.state.searchItemAddress) { //condition2
modItemList = (
this.props.items.filter(
(item) => item.fullAddress.some(e => e.toLowerCase().indexOf(lcAddress) !== -1) // For Address
)
);
}
This is where it's a little tricky to explain.
Now I want to add a 3rd condition, which happens only if both condition1 and condition2 are met, AND the outcome is that of executing code from condition1 and condition2.
How would I go about expressing that?
I think you just want to use two separate if conditions where both may run, not if/else if:
let modItemList = this.props.items;
if (this.state.searchItemName) { // condition1
modItemList = modItemList.filter(item =>
item.name.toLowerCase().indexOf(lcName) !== -1 // For name
);
}
if (this.state.searchItemAddress) { //condition2
modItemList = modItemList.filter(item =>
item.fullAddress.some(e => e.toLowerCase().indexOf(lcAddress) !== -1) // For Address
);
}
Nothing is asynchronous here or involves promises. If it did, I would recommend to just place an await in the respective location.
There's no asynchronous action here, so no need to track an async action with a promise.
Probably the simplest thing is to filter the filtered list:
let modItemList = this.props.items;
if (this.state.searchItemName) {
modItemList = modItemList.filter(item => item.name.toLowerCase().includes(lcName));
}
if (this.state.searchItemAddress) {
modItemList = modItemList.filter(item => item.fullAddress.some(e => e.toLowerCase().includes(lcAddress)));
}
Or filter once and check for searchItemName and searchItemAddress within the callback:
let modItemList = this.props.items.filter(item =>
(!this.state.searchItemName || item.name.toLowerCase().includes(lcName)) &&
(!this.state.searchItemAddress || item.fullAddress.some(e => e.toLowerCase().includes(lcAddress));
Even if the list is in the hundreds of thousands of entries, neither of those is going to be slow enough to worry about.
Or if it really bothers you do do that double-filtering or re-checking, build a filter function:
let modItemList;
let filterFunc = null;
if (this.state.searchItemName && this.state.searchItemAddress) {
filterFunc = item => item.name.toLowerCase().includes(lcName) && item.fullAddress.some(e => e.toLowerCase().includes(lcAddress));
} else if (this.state.searchItemName) {
filterFunc = item => item.name.toLowerCase().includes(lcName);
} else if (this.state.searchItemAddress) {
filterFunc = item => item.fullAddress.some(e => e.toLowerCase().includes(lcAddress));
}
modItemList = filterFunc ? this.props.items.filter(filterFunc) : this.props.items;
That involves repeating yourself a bit, though, leaving open the possibility that you'll update one address filter but not the other. You can aggregate the filter functions:
let nameCheck = item => item.name.toLowerCase().includes(lcName);
let addressCheck = item => item.fullAddress.some(e => e.toLowerCase().includes(lcAddress));
let modItemList;
if (this.state.searchItemName && this.state.searchItemAddress) {
modItemList = this.props.items.filter(item => nameCheck(item) && addressCheck(item));
} else if (this.state.searchItemName) {
modItemList = this.props.items.filter(nameCheck);
} else if (this.state.searchItemAddress) {
modItemList = this.props.items.filter(addressCheck(item);
}
If there were more than two, we might look at putting them in an array and doing
modItemList = this.props.items.filter(item => arrayOfFunctions.every(f => f(item)));
So...lots of options. :-)
I've used includes(x) rather than indexOf(x) !== -1 above. I find it clearer.
You would still need to wait with the action till promise is resolved and finished. So you would check the conditions inside of promise callback and then make adequate actions. Until you have resolved promise, you can display some "loading" information.
Maybe this solution You want?
if (condition1 & condition2) {
something = this.props.something.filter(1)).then(this.props.something.filter(2)
} else if (condition1) {
something = this.props.something.filter(1)
} else if (condition2) {
something = this.props.something.filter(2)
}

Nested map is not rendering the Redux State Correctly

I am new to react js. I am creating a comparison between user typing and actual sentence to be typed Somehow I am able to achieve this but It is not perfect like nested map is not rendering properly if letter typed correctly it should render green background My state is updated properly But my nested map Kinda not working there is a delay
Component Code
renderLine = () => {
let test = this.props.test.get('master')
return test.map(line => {
return line.check.map( (ltr,i) => ltr.status ? <span key={i} className="correct">{ltr.letter}</span> : ltr.letter )
})
};
handleKeyPress = e => {
if(e.charCode === 32) {
this.setState({
pushToNext:true,
currentTyping:""
})
}
};
handleInput = e => {
if(e.target.value !== " "){
let {storeValue} = this.state;
console.log(storeValue.length);
let updatedWord = e.target.value;
let updateArr = [];
if(storeValue.length === 0){
updateArr = storeValue.concat(updatedWord)
}else {
if(this.state.pushToNext){
updateArr = storeValue.concat(updatedWord)
}else {
storeValue.pop();
updateArr = storeValue.concat(updatedWord);
}
}
this.setState({
currentTyping:updatedWord,
storeValue:updateArr,
pushToNext:false
},() => {
let {storeValue} = this.state
let lastWordIndex = storeValue.length === 0 ? storeValue.length : storeValue.length - 1;
let lastLetterIndex = storeValue[lastWordIndex].length === 0 ? storeValue[lastWordIndex].length : storeValue[lastWordIndex].length - 1;
let lastWordValue = storeValue[lastWordIndex];
let lastLetterValue = lastWordValue[lastLetterIndex];
// console.log(lastWordIndex,lastLetterIndex,lastWordValue,lastLetterValue,"After tstae")
return this.props.compareCurrentTextWithMater(lastWordIndex,lastLetterIndex,lastWordValue,lastLetterValue)
});
}
};
Redux Reducer
import {FETCH_USER_TYPING_TEXT,COMPARE_TEXT_WITH_MASTER} from "../actions/types";
import {fromJS} from 'immutable';
const initialState = fromJS({
text:null,
master:[],
inputBoxStatus:false
});
export default function (state = initialState,action) {
switch (action.type){
case FETCH_USER_TYPING_TEXT:
return setTextManipulated(state,action);
case COMPARE_TEXT_WITH_MASTER:
return compareTextWithMaster(state,action)
default:
return state
}
}
const compareTextWithMaster = (state,action) => {
let {lastWordIndex,lastLetterIndex,lastLetterValue} = action;
let masterWord = state.get('master')[lastWordIndex];
let masterLetter = masterWord.check[lastLetterIndex];
let newState = state.get('master');
if(typeof masterLetter !== "undefined"){
if(masterLetter.letter === lastLetterValue){
masterWord.check[lastLetterIndex].status = true;
newState[lastWordIndex] = masterWord;
return state.set('master',newState)
}else {
masterWord.check[lastLetterIndex].status = false;
newState[lastWordIndex] = masterWord;
return state.set('master',newState)
}
}else {
console.log('Undefinedd Set Eroing or wrong Space Chratced set Box Red Colot',newState);
}
};
UPDATE
I did the same Logic with plain React.js it works Perfectly and nested map rendering the if else logic properly there is no on letter delay
https://codesandbox.io/s/zx3jkxk8o4
But the same logic with Redux State with immutable js Does'nt take effect with nested loop if else statement I don't know where the problem Relies ..and My Code Snippet will be little bit different from CodeSanbox COde But the Logic is Same
Probably, the diffing algorithm of react does see that oldState === newState and skips the re rendering. To avoid that situation, use a new object in the root of the state so that the above check returns false. I see that you use immutableJs, so maybe force re-render with componentShouldUpdate method instead.
Also consider using dev tools to step through the code line by line to see what is going on.
If nothing at all works, switch to something simpler with less dependencies and go from there, incrementally adding what you need.

Categories

Resources