I'm trying to have an onClick event fire depending on the location of the user.
if the location is '/favorites' i want to return null i've tried using a ternary operator to achieve this, and cannot find my mistake. heres what i've tried:
{this.props.location==='/favorites' ? null :
onClick={() => {
this.props.updateFavsState(this.props.character);
this.setState(prevState => ({
loved: !prevState.loved
}));
}}
}
Put logic in the function and call function onClick event, location pass to the function as argument.
Solution:
handleClick = (location) => {
if (location === '/favorites') {
return null;
}
this.props.updateFavsState(this.props.character);
this.setState(prevState => ({
loved: !prevState.loved
});
}
// somewhere in your render component
onClick={() => { handleClick(this.props.location)}}
what you want is
onClick={this.props.location==='/favorites' ? null :
() => {
this.props.updateFavsState(this.props.character);
this.setState(prevState => ({
loved: !prevState.loved
}));
}}
Related
So I want to update the previous properties of my state with array of objects.Initially I made only two objects.I want to implement bookmark functionality in my moviedb app.When I click on the icon it should change color as well as change the value of isFavorited property in my useState.
const [isActive, setActive] = useState({
favorited: false,
customColor: "white"
});
const handleToggle = () => {
setActive({ ...isActive, !favorited});
if(isActive.favorited){
setActive( {...isActive, customColor: "red"});
}else{
setActive( {...isActive, customColor: "white"});
}
}
I am calling the handleToggle function on clicking a icon.How to make it so that the value of favorited toggles everytime I click it using useState?I get a error squiggle on !favorited
Writing {...isActive, !favorited} is not a valid JS syntax.
Try rewriting the function to:
const handleToggle = () => {
setActive((prevState) => {
return {
...prevState,
favorited: !prevState.favorited,
customColor: prevState.favorited ? "red" : "white",
};
});
};
You should update the state by using the prevState :-
setActive((prevState) => ({
...prevState, favorited : !favorited}
));
I am using Material UI for a component library and noticed when I click a button within a Dialog or Alert (both components manage states of open/closed), I get a memory leaks warning. I am unsure of how to fix the problem here. The button component uses state to create an active class when clicked, which uses a setTimeout onClick to make the button click more visible/longer lasting in the UI.
This is the button component:
function Button({
classes,
className,
onClick,
...props
}) {
let [active, setActive] = useState(false);
let handleClick = e => {
e.persist();
setActive(true);
setTimeout(() => {
setActive(false);
}, 250);
if (typeof onClick === "function") onClick(e);
};
return (
<MuiButton
variant={finalVariant(variant)}
className={`${active ? "Mui-active" : ""} ${className}`}
classes={buttonClasses}
onClick={handleClick}
{...props}
/>
);
}
let containedStyle = color => ({
"&:active": {
backgroundColor: color.dark
},
"&.Mui-active": {
backgroundColor: color.dark
}
});
This is the memory leaks warning I get when I click a button inside either an Alert or Dialog component:
index.js:1437 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
I've tried using useEffect as suggested by the warning to clear the active state but haven't had luck. Here is a demo of what happens when I use a custom button built with MUI that uses hooks to manage state when the button is used in a dialog or alert https://codesandbox.io/s/traffic-light-using-hooks-zpfrc?fontsize=14&hidenavigation=1&theme=dark
This happens because your handleClick function uses setTimeout:
let handleClick = e => {
e.persist();
setActive(true);
setTimeout(() => {
setActive(false);
}, 250);
if (typeof onClick === "function") onClick(e);
};
To update the state.
The component is getting unmounted by the parent component when onClick is called, but there is still a subscription (your timeout) kept alive.
This isn't really a big deal if it's a one-off event, like in this case. It's a warning, not an error. The main purpose of this warning is to let you know if you are keeping subscriptions or references around for a long time after something is unmounted.
There are a few work-arounds to get rid of the warning by setting a flag if the component is unmounted and, if the flag is set, not updating state, but that doesn't really solve the problem that there is a reference to a component kept around after it's unmounted.
A better way of resolving this problem would be to keep a reference to the timeout using React.useRef() and then clearing it in useEffect(), like this:
function Button({
classes,
className,
onClick,
...props
}) {
let [active, setActive] = useState(false);
+ const timeout = React.useRef(undefined);
+ React.useEffect(() => {
+ return () => {
+ if (timeout.current !== undefined) {
+ clearTimeout(timeout.current);
+ }
+ }
+ }, []);
let handleClick = e => {
e.persist();
setActive(true);
- setTimeout(() => {
+ timeout.current = setTimeout(() => {
setActive(false);
}, 250);
if (typeof onClick === "function") onClick(e);
};
return (
<MuiButton
variant={finalVariant(variant)}
className={`${active ? "Mui-active" : ""} ${className}`}
classes={buttonClasses}
onClick={handleClick}
{...props}
/>
);
}
This could be encapsulated in a hook like so:
function useSafeTimeout() {
const timeouts = React.useRef([])
React.useEffect(() => {
return () => {
timeouts.forEach(timeout => {
clearTimeout(timeout)
})
}
}, [])
return React.useCallback((fn, ms, ...args) => {
const cancel = setTimeout(fn, ms, ...args)
timeouts.current.push(cancel)
}, [])
}
And used in this manner:
function Button({
classes,
className,
onClick,
...props
}) {
let [active, setActive] = useState(false);
+ const setTimeout = useSafeTimeout();
let handleClick = e => {
e.persist();
setActive(true);
setTimeout(() => {
setActive(false);
}, 250);
if (typeof onClick === "function") onClick(e);
};
return (
<MuiButton
variant={finalVariant(variant)}
className={`${active ? "Mui-active" : ""} ${className}`}
classes={buttonClasses}
onClick={handleClick}
{...props}
/>
);
}
Here is my solution for the problem:
function Button({
classes,
className,
onClick,
...props
}) {
let [active, setActive] = useState(false);
let timeoutIds = useRef([]);
let registerTimeout = (f, ms) => {
let timeoutId = setTimeout(f, ms);
timeoutIds.current.push(timeoutId);
};
let handleClick = e => {
e.persist();
setActive(true);
if (typeof onClick === "function") onClick(e);
};
let cleanup = () => {
timeoutIds.current.forEach(clearTimeout);
};
useEffect(() => {
if (active === true) {
registerTimeout(() => setActive(false), 250);
}
return cleanup;
}, [active]);
return (
<MuiButton
variant={finalVariant(variant)}
className={`${active ? "Mui-active" : ""} ${className}`}
classes={buttonClasses}
onClick={handleClick}
{...props}
/>
);
}
I'm using React Hooks. I set the state property questions after an axios fetch call. Now when I click a button, in its function questions state is still empty
const [questions, setQuestions] = useState([]);
const [customComponent, setCustomComponent] = useState(<div />);
useEffect(() => {
axios.get("urlhere").then(res => {
console.log(12, res.data);
setQuestions(res.data);
res.data.map(q => {
if (q.qualifyingQuestionId == 1) {
setCustomComponent(renderSteps(q, q.qualifyingQuestionId));
}
});
});
}, []);
const handleNext = i => {
console.log(32, questions); //questions is still an empty array here
};
const renderSteps = (step, i) => {
switch (step.controlTypeName) {
case "textbox":
return (
<div key={i}>
<input type="text" placeholder={step.content} />
<button onClick={() => handleNext(i)}>Next</button>
</div>
);
}
};
return <>{customComponent}</>;
Do I need to use reducers here and put the custom component in another "file"?
setQuestions does not update state immediately, you should use the prevState instead to access the new value.
Here's a sandbox to match your codes with some explanation on why it was empty > https://codesandbox.io/s/axios-useeffect-kdgnw
You can also read about it here: Why calling react setState method doesn't mutate the state immediately?
Finally I have my own solution
I passed down the data from the fetch function to another component as props
useEffect(() => {
axios.get('url')
.then((data) => {
setCustomComponent(<Questions questions={data} />)
})
}, [])
I have a series of buttons that execute internal logic(no forms not dependant on input), but call the functions asynchronously. I would like to disable the button after one click, and have tried several things on onclick() method but keep getting errors.
Code looks something like this:
{ this.state.isEthTransferVisible && <button id="button"
onClick={() => { parseAddress(this.state.sc);}, this.handleTransferFromEthereum}>Check Balances</button>
}
this is the function called from within the onclick
async handleTransferFromEthereum(){
await parseAddress(this.state.sc)
this.setState(prevState => ({
isEthTransferVisible: !prevState.isEthTransferVisible,
isGoDeployedVisible: !prevState.isGoDeployedVisible
}));
}
Add another state variable, such as this.isEthTransferEnabled (Default true). Change your button to:
{ this.state.isEthTransferVisible && <button id="button"
disabled={this.state.isEthTransferEnabled}
onClick={() => { parseAddress(this.state.sc);}, this.handleTransferFromEthereum}>Check Balances</button>
}
And change your handleTransferFromEthereum method:
async handleTransferFromEthereum(){
this.setState({ isEthTransferEnabled: false });
await parseAddress(this.state.sc)
this.setState(prevState => ({
isEthTransferVisible: !prevState.isEthTransferVisible,
isEthTransferEnabled: true,
isGoDeployedVisible: !prevState.isGoDeployedVisible
}));
}
onClick={() => { parseAddress(this.state.sc);}, this.handleTransferFromEthereum}
Wrong syntax? It should be:
onClick={() => {
parseAddress(this.state.sc);
this.handleTransferFromEthereum();
}}
i am new to react. please help me.
i am trying the get a value of data outside render.
data.map(
<button onClick = { () => { console.log (data)}}></button>
)
i am getting the value of data here. but
handleClick = () => {
console.log (data) /// not getting the value
}
<button onClick = { this.handleClick}></button>
if i try this.hadleClick , then i am not getting any value. why . thanks,
It's because you are not passing the value to your handleClick function. A couple options:
Bind the function with the params in your onClick:
data.map(
<button onClick = { this.handleClick.bind(this, data) }></button>
)
Pass an anonymous function to your click handler:
data.map(
<button onClick = { () => this.handleClick(data) }></button>
)
And you'll need to update your handleClick function to accept data as a param:
handleClick = data => {
console.log(data);
}
You should be passing the data you want to print to the function like below:
<button onClick = { () => this.handleClick(data) }></button>
(and your handler function should accept it as well)
handleClick = (data) => console.log(data);