I have a listener that sets the state if the value exists. It previously worked fine when I just had one value like so.
subscribe('feature-settings-updated', (evt, enabledFeatures) => {
setIsEnabled(enabledFeatures.includes('showEmployeesReport'));
});
Now I have a second value and rather than duplicating the code I want to do it so that it takes an array and if either one of the value exists then set it to true. Following is my attempt but it only enables it for just the one. Any ideas?
const features = ['showEmployeesReport', 'showCustomersReport'];
subscribe('feature-settings-updated', (evt, enabledFeatures) => {
setIsEnabled(
features.some(exp => enabledFeatures.includes(exp))
);
});
You seem to reference the wrong variable (experiments instead of features):
const features = ['showEmployeesReport', 'showCustomersReport'];
subscribe('feature-settings-updated', (evt, enabledFeatures) => {
setIsEnabled(
features.some(feature => enabledFeatures.includes(feature))
);
});
Related
I have useState "setAnswers" (set) and "answers" (get) (answers is array with strings)
and click trigger:
onClick = () => {
setAnswers((prev) => [...prev, e])
setValue(questionKey, answers)
console.log(watch(questionKey))
}
but with ever click i got only previous value
In fact, your console.log is execute before the state finish to be calculated, if you put your console.log on an other place, normally, you find what you want.
Try it, and say me
Your console.log(watch(questionKey)) all time will go wrong on onChange.
you need use a useEffect to log or make anything else with state as base.
useEffect(() => {
console.log(watch(questionKey)
}, [questionKey]);
to more info you can read here:
https://dev.to/mpodlasin/react-useeffect-hook-explained-in-depth-on-a-simple-example-19ec
I think you are a little bit confused: watch function from useForm is used to
Watch specified inputs and return their values.
So console.log(watch(questionKey)) does make no sense.
watch should be used in this way:
React.useEffect(() => {
const subscription = watch((value, { name, type }) => console.log(value, name, type));
return () => subscription.unsubscribe();
}, [watch]);
You use a useEffect to subscribe/unsubscribe watch on some form fields, and then in component's body you could call:
const watchSomething = watch(<something>);
and, every time the field called <something> will change his value, watch will execute console.log(value, name, type).
If you want to print the very last value of a state variable, you should know that setValue, setAnswer are async functions and its absolutely not guaranteed that on next line you could log the last value.
To solve your problem you have 2 choices:
use watch correctly;
forget watch and use classic useEffect:
onClick = () => {
setAnswers((prev) => [...prev, e])
setValue(questionKey, answers)
}
useEffect(() => {
console.log(questionKey); //<-- here you will print the very last value of questionKey
}, [questionKey]);
Here a guide on how to use watch.
Im using the .filter() method on an object inside of a useEffect() method to filter out certain arrays out by name if they exist in a second object. I need to get the difference of arrays back into a useState() method. Im using the following and works outside the useEffect() method:
useEffect(() => {
getDBData().then( (r) => { setAnotherObj(r); });
getAPICall().then((r) => {
let result = r.filter(
(o1) => !anotherObj.filter((o2) => o1.name === o2.name)
);
setOption(result);
});
}, []);
Now that works outside of the useEffect method when I add it to an event like onClick, but not inside, it might work one time then it doesn't at all. What am I missing about the useEffect method that I need to know why the filtering isn't being done?
Replace second filter with find.
!anotherObj.filter(o2 => o1.name === o2.name) will always return false, be it has elements or not.
There is no dependency array in the in the useEffect, so whenever there is a state change, this useEffect gets triggered again.
Finding A-B, filter all the elements of A that are not in B.
r.filter(o1 => anotherObj.find(o2 => o1.name !== o2.name)); With this it removes all the elements that are common in A and B. And leaves out only elements in A.
Update as follows,
useEffect( () => {
getAPICall().then( (r) => {
const result = r.filter(o1 => anotherObj.find(o2 => o1.name !== o2.name));
setOption(result);
});
}, []);
I'm a React/ES6 beginner and I'm using this code I found to handle a checkbox inside a custom component being clicked (the custom component includes a material-ui CheckBox, hence the "checked" value). I'm planning on adding more fields to the custom component, such as a textbox that corresponds to the checkbox where the user can add more information about the box they checked.
Anyway, I'm a bit confused about what's going on in that first line. I was hoping one of you senior level devs could break it down for me so i can understand what's happening here.
Two things to note:
index console logs as an integer value (position in my mapped array)
checked is false by default but console logs as true (is it being
toggled true somehow?)
const onMediaDeliverableChange = index => ({ target: {checked} }) => {
console.log('>> [form.js] (onMediaDeliverablesChange) index = ',index);
console.log('>> [form.js] (onMediaDeliverablesChange) target = ',checked); }
Here's an example of code that I took this from, that is working.
const onCheckBoxChange = index => ({ target: { checked } }) => {
const newValues = [...values];
const value = values[index];
newValues[index] = { ...value, checked };
console.log('>> [form.js] (onCheckBoxChange) value = ',value, index);
console.log('>> [form.js] (onCheckBoxChange) newValues[index] = ',newValues[index]);
props.setDesignOrDigital(newValues);
};
The following:
const onCheckBoxChange = index => ({ target: { checked } }) => {
// stuff
};
could also be written as:
const onCheckBoxChange = index => (event) => {
const checked = event.target.checked;
// stuff
};
{ target: { checked } } is an example of using object destructuring on a function argument. In this case, the argument would be an event.
The first part:
index => another-function
is, as svey mentioned in the comments, an example of a curried function. I assume onCheckBoxChange was used in a loop where the index of the checkbox being rendered was passed in which then returns a function that is an event handler for the change event. The index is then used to get/set the checked state for the respective checkboxes.
I am trying to filter an array with a string that is input by user. The results are not updating properly with the first key input, then if the box is cleared or characters removed/changed, results that may now pass the filter are not being displayed.
The goal is to have all results displayed on initial page render, then properly updated with each keystroke.
Apologies; I'm just learning to code. Thanks for all assistance.
searchCompUsers = () => {
const newState = {}
const filteredEmps = this.props.employees.filter(
user => user.name.includes(this.state.searchName)
)
console.log(filteredEmps)
`` newState.filterEmps = filteredEmps
this.setState(newState)
}
empSearch = evt => {
const stateToChange = {};
stateToChange[evt.target.id] = evt.target.value;
this.setState(stateToChange);
this.searchCompUsers()
};
These lines are being run in sequence:
this.setState(stateToChange);
this.searchCompUsers();
...
const filteredEmps = this.props.employees.filter(
user => user.name.includes(this.state.searchName)
)
...
this.setState(newState);
I am assuming in your example, evt.target.id is searchName.
Two things you're doing here which you shouldn't do:
Running two setStates in sequence. This isn't necessarily a problem, but there's generally no reason for it and it could mean your code is structured poorly.
Referencing the state immediately after setState. setState is run asynchronously, so you can't guarantee the state will be updated by the time you reach your filter.
The weird results you're getting are probably stemming from (2).
Something like this would work better, assuming the rest of your code is fine:
empSearch = evt => {
const key = evt.target.id;
const value = evt.target.value;
if (key === "searchName") {
const filteredEmps = this.props.employees.filter(
user => user.name.includes(value);
);
this.setState({
filterEmps: filteredEmps
});
}
};
This way, you're only calling setState once per event, and you're not relying on the results of an earlier setState.
If you need to keep searchName in the state for some reason (such as using a controlled component), then you can simply add it to the same setState.
this.setState({
filterEmps: filteredEmps,
searchName: value
});
The only places you can assume the state is up-to-date is in the render() function, and in certain React lifecycle functions. You can also provide a callback to setState if necessary, though this should be relatively rare: this.setState({ ...someState }, () => { ...someCodeToRun() });
// ticker$ will update every 3s
// showHand$ will only triger after user click button
// I would like to take last ticker price as user order price when user click button
let lastPrice: number;
this.ticker$
// What I am doing now is preserve value to vairable here.
.do(ticker => lastPrice = ticker.closePrice)
.switchMap(() => this.showHand$)
.subscribe(showHand => {
// use value here
this.order.price = lastPrice;
this.order.amount = showHand.amount;
this.order.type = showHand.type;
this.submit();
});
Any segestion about how to prevser value and switch map together, without one line variable like above?
Results selector function is deprecated in version 6 will be removed in version 7.
From docs:
https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md#result-selectors
with resultSelector (v5.x)
source.pipe(
switchMap(fn1, fn2)
)
the same functionality without resultSelector, achieved with inner map
source.pipe(
switchMap((a, i) => fn1(a, i).pipe(
map((b, ii) => fn2(a, b, i, ii))
)
)
The behaviour you require is already possible with an overload of SwitchMap with a selectorFunc for the combination of every (outerValue,innerValue):
this.ticker$
.switchMap(
() => this.showHand$,
(tickerValue, switchMap) => tickerValue
)
.subscribe(showHand => { });
There is a little hack to achieve this - basically you have a whole new observable inside the switchmap, and this observable has access to the value passed into the switchmap function. You can use this value in an inner map to preserve the value.
this.ticker$
.switchMap(ticker => this.showHand$.pipe(map(hand => ({ ticker,hand }) ))
.subscribe( obj => {
// use value here
this.order.price = obj.ticker;
this.order.amount = obj.hand.amount;
this.order.type = obj.hand.type;
this.submit();
});
I think this is the operator
this.showHand$.take(1)
.withLatestFrom(this.ticker$)
.subscribe(([showHand, ticker]) => {
this.order.price = ticker.closePrice;
this.order.amount = showHand.amount;
this.order.type = showHand.type;
this.submit();
});
Note, take(1) will close subscription, but if you want the user to be able to press the button many times, save the subscription to a const and unsubscribe when finished.