How can i update the value to use in other function? - reactjs

I am using useState for this object 'selected', i want to get the updated value in this function verifyActive
const [selected, setSelected] = useState({ a: '', b: '' })
and i have a function that is active since a button
const setActive = (value) => {
setSelected({ ...selected, b: value })
verifyActive()
}
const verifyActive=()=>{
console.log('selected', selected) // is not updated
}
...
console.log(selected) //here is value is updated
return (
<button
onchange={(value) => { setActive(value) }}
/>

The local const selected is never going to change, but what you can do is save the new state to a variable, and pass it in to verifyActive:
const setActive = (value) => {
const newState = { ...selected, b: value };
setSelected(newState);
verifyActive(newState);
}
const verifyActive = (value) => {
console.log('selected', value);
}

change your setActive to this way
const setActive = (value) => {
setSelected((prevSelected) => { ...prevSelected, b: value })
verifyActive()
}

Related

How can i change the object value in map

***//How can I change the select value to true of the checked object?***
const App = () => {
const data = [{id:1, msg:"t", select:false}, {id:2, msg:"t2, select:false}]
const handleChange = (e) => {
if(checked){
data.select === true
}
}
//``To check the particular object I want to set the value true for that object and rendered the false as an unchecked value
return(
{data.map(d => {
<Checkbox
value={d}
checked={d.select}
onChange-{handleChange}
/>
}
)
}
You just have to pass the id to handleChange like this:
return(
{data.map(d => {
<Checkbox
value={d}
checked={d.select}
onChange-{(e)=>handleChange(e,d.id)}
/>
}
and change handleChange to be something like this
const handleChange = (e,id) => {
const index = data.findIndex(element => element.id === id) // here we get the index of the element
if(checked){
data[index].select = true
}
}

React custom hook: Is there a way to set a property dynamically?

I have a row of headers in which I would like to attach a clickHandler to control the ASC and DESC of data for their respective column.
My brute force attempt was to loop all the headers and create an object which would have a property to represent each header with a value to let the hook know which is active or not i.e. in ASC or DESC:
{ 1: false, 2: false, 3: false....}
The code:
function addPropToObj(arr) {
var obj = {}
arr.forEach(o => {
obj[o.id] = false;
})
return obj;
}
const activeObj = addPropToObj(userData)
function useActiveToggle(initialState = activeObj, bool = false) {
const [state, setState] = React.useState(initialState);
const toggle = React.useCallback((id) => {
return setState((previousState) => ({ ...previousState, [id]: !previousState[id] }))
}, [])
return [state, toggle]
}
They're only 199 objects in the array, but what if there were 1000, or 10,000?
I know I've heard objects are cheap in JS but it doesn't feel right.
So I tried this:
function useActiveToggle(initialState = {}, bool = false) {
const [state, setState] = React.useState(initialState);
const toggle = React.useCallback((id) => {
return setState((previousState) => {
if (!previousState[id]) {
previousState = { ...previousState, ...{ [id]: true } }
}
return ({ ...previousState, [id]: !previousState[id] })
})
}, [])
return [state, toggle]
}
But that results in a mess! Strange behaviors!
A part of me thinks my brute force idea might not be too horrible, correct me if I'm wrong but how could react do something like this with all the reconciliation it has to deal with?
Anyone have an idea how to approach this?
Just guessing this is what you want?
function useActiveToggle(initialState = {}, bool = false) {
const [state, setState] = React.useState(initialState);
const toggle = React.useCallback((id) => {
setState((previousState) => { // not "return setState", just do "setState"
const prevValue = Boolean(previousState[id]); // get previous value, undefined also equals to false
const nextState = {
...previousState,
[id]: !prevValue, // invert the value
};
return nextState;
});
}, [])
return [state, toggle]
}

Rsuite TreePicker clear selections programmitacally - ReactJS

I am using TreePicker & CheckTreePicker from rsuite package.
I would like to clear the selections programmatically for the tree picker when certain props value is changed. I am able to trigger event in the useEffect when value of selectItemchanges , and I would like to clear all the current selections for treePicker just after it.
const Categories = ({ selectItem }) => {
useEffect(() => {
// INCLUDE LOGIC HERE TO RESET ALL THE FILTERS WHEN the value of selectItem change
}, []);
const handleCategFilters = (value) => {
console.log("do something here with value", value);
};
return (
<CheckTreePicker
data={pickerDT}
onChange={(i) => {
handleCategFilters(i);
}}
/>
);
};
I appreciate yur help. Thank you.
You can manually control the value
const Categories = ({ selectItem }) => {
const [value, setValue] = React.useState([]);
useEffect(() => {
// INCLUDE LOGIC HERE TO RESET ALL THE FILTERS WHEN the value of selectItem change
setValue([]);
}, []);
const handleCategFilters = (value) => {
console.log("do something here with value", value);
};
return (
<CheckTreePicker
data={pickerDT}
value={value}
onChange={(i) => {
handleCategFilters(i);
}}
/>
);
};

update the state object after the event tigger using functional component react

I' m using the useContext hook to manage the state, i have tigger the handleChange method from the other component's input slider field, this changes the state object and that state are used to filter the data
this is the context API hook component
handleChange is tigger by the other component input price slider
const handleChange = (event) => {
const target = event.target;
const name = target.name;
const value = target.value;
setState(
{
...state,
[name]: value,
},
**Part 1
filterBooks()
);
};
const filterBooks = () => {
let { books, maxPrice, minPrice, type, category, price } = state;
let tempBook = [...books];
price = parseInt(price);
// console.log(typeof price);
// console.log(tempBook, price);
if (type !== "all") {
tempBook = tempBook.filter((book) => book.type === type);
}
tempBook = tempBook.filter((book) => book.price < price);
**Part 2 **
*code works as expected till here*
setState({
...state,
sortedBook: tempBook,
});
// how to update state in this scenario;
// as per the docs we can't update state in nested function
};
return (
<ProductContext.Provider value={{ state, handleChange }}>
{props.children}
</ProductContext.Provider>
);
};
export default ProviderContext;```
Not sure why you're filtering in the setState callback, why not just update the filter in the initial setState?
Also, unless your state is deeply nested you shouldn't need to pass the full state to the setState, and if it is nested - I'd consider a redux implementation
I refactor the code and it worked
const handleChange = (event) => {
const target = event.target;
const name = target.name;
const value = target.value;
setFlag(false);
setState({
...state,
[name]: value,
sortedBook: [],
});
setFlag(true);
};
useEffect(() => {
if (!flag) {
// console.log("effect called without change - by default");
} else {
// console.log("effect called with change ");
const filterBooks = () => {
let { books, maxPrice, minPrice, type, category, price } = state;
let tempBook = [...books];
if (type !== "all") {
tempBook = tempBook.filter((book) => book.type === type);
}
tempBook = tempBook.filter((book) => book.price < parseInt(price));
// console.log("from tempbook", tempBook);
setState({
...state,
sortedBook: tempBook,
});
};
filterBooks();
}
// console.log(state);
}, [state.price, flag]);

is there a way to shorten this change handler that uses hooks in React?

With class based components you could use the computed properties to in order to use one single handler for several inputs with the help of an id attribute like this:
function handleChange(evt) {
const value = evt.target.value;
setState({
...state,
[evt.target.name]: value
});
}
This is thebest I caome up with but im sure there must be a shorter way:
const handleChange = (e) => {
if (e.target.id === 'name') setName(e.target.value)
if (e.target.id === 'genre') setGenre(e.target.value)
if (e.target.id === 'description') setDescription(e.target.value)
}
Any ideas?
Thanks.
You could have create an object in the useState and update just like the first example.
// Declare the state with a object default value
const [state, setState] = useState({})
const handleChange = (e) => {
setState(prev => ({
...prev,
[e.target.id]: e.target.value
}))
}
If you can't change the useState and have a very strong reason to have these 3 separeted useStates, you could create an object that returns the 3 functions based on the e.target.id
const updater = {
name: setName,
genre: setGenre,
description: setDescription,
}
And when updating you do
const handleChange = (e) => {
const updateValue = updater[e.target.id]
if (updateValue) {
updateValue(e.target.value)
}
else {
// No function to update found
// Do something else
}
}

Resources