You are not changing state in right manner, Code for change state will be like this this.setState({ showCart: true})
Replace handleClick function from below code.
handleClick() {
this.setState({ showCart: true})
console.log("button clicked")
}
Answer from Nishant Dixit on Stack OverflowYou are not changing state in right manner, Code for change state will be like this this.setState({ showCart: true})
Replace handleClick function from below code.
handleClick() {
this.setState({ showCart: true})
console.log("button clicked")
}
You update your state the wrong way :)
handleClick() {
this.setState({ showCart: true})
console.log("button clicked")
}
How to toggle boolean state of a React component?
How to conditionally add or not onClick on a div in react?
reactjs - Warning: Expected `onClick` listener to be a function, instead got a value of `boolean` type - Stack Overflow
React needs two clicks to update boolean state when triggering button onClick event
If your new state update depends on the previous state, always use the functional form of setState which accepts as argument a function that returns a new state.
In your case:
this.setState(prevState => ({
check: !prevState.check
}));
See docs
Since this answer is becoming popular, adding the approach that should be used for React Hooks (v16.8+):
If you are using the useState hook, then use the following code (in case your new state depends on the previous state):
const [check, setCheck] = useState(false);
// ...
setCheck(prevCheck => !prevCheck);
Update [May 2023]:
Relevant section in docs: https://react.dev/reference/react/useState#updating-state-based-on-the-previous-state
You should use this.state.check instead of check.value here:
this.setState({check: !this.state.check})
But anyway it is bad practice to do it this way. Much better to move it to separate method and don't write callbacks directly in markup.
Upd: As pointed out in comments this approach might lead to unexpected results since React's state is asynchronous. The correct way in this case will be to use callback:
this.setState(({ check }) => ({ check: !check }));
Put the condition like this:
onClick={canClick ? this.handler : undefined }
Working Code:
class App extends React.Component {
_click(){
// it will not print the value
console.log('yes');
}
render(){
return (
<div>
<div onClick={false ? this._click : undefined }>Click</div>
</div>
)
}
}
ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
You can treat the elements attributes (like onClick) as object properties. Use the spread operator to only on condition, spread the onClick:
<div
{...(canClick && { onClick: this.handler })}
>
hello
</div>
You are overriding the definition of toggle with this code :
const [toggle] = useAudio(url);. The Player.js has multiple declarations and definitions of toggle. See:
const toggle = () => {
setPlaying(!playing);
playing ? audio.play() : audio.pause()
console.log("audio is playing" + toggle);
};
return [playing, toggle];
};
..
...
..
const [toggle] = useAudio(url);
Hence the Error Expected OnClick to be a function but provided a boolean
Thank you for your feedback! I managed to get everything to work by changing my code in Player.js to:
import React, { useState } from "react";
import "./Button.css";
import {useTranslation} from "react-i18next";
import teaser from '../sounds/teaser-final.mp3';
const Player = () => {
const [playing, setPlaying] = useState(true);
const [audio] = useState(new Audio(teaser));
const toggle = () => {
setPlaying(!playing);
playing ? audio.play() : audio.pause()
};
const {t} = useTranslation('common');
return (
<div>
<audio id="player" style={{'display': 'none'}} src={teaser}></audio>
<button
className="btns hero-button btn--outline btn--large"
onClick={toggle}
>
{t('heroSection.button')}
</button>
</div>
);
};
export default Player;
Whenever you want to pass a prop to a child component (Main) from your parent component (Category) you pass it in render() function as:
render(){
<Main
isOpen={this.state.isOpen}
/>
}
But i don't see you importing the child component (Main) at all or using it in the render function of your parent component (Category).
You need to use a child component in parent's render function in order to pass the state (and even props) of Parent component to its child component.
You can get more info from the React Docs as well.
https://facebook.github.io/react/docs/components-and-props.html
Per React's Thinking in React documentation, props are "a way of passing data from parent to child."
For your example, the parent component Gallery has to include the child component Main in the render function in order to make it works.
class Main extends Component {
render() {
const botStatus = this.props.isOpen ? "isOpen" : "noOpen";
return (
<div>
<div>
<h1>{botStatus}</h1>
</div>
</div>
);
}
}
class Gallery extends Component {
constructor() {
super();
this.state = {
isOpen: false
};
}
render() {
return(
<div>
<div>
<Main isOpen={this.state.isOpen}/>
</div>
</div>
);
}
}
Normal OOP design principles don't always apply directly to React components. Components don't usually have instance properties, they mostly just have props and state (there are a few exceptions where you do use an instance property, like Animation objects in react-native, but these are rare).
You're kind of mixing the two things in a way that doesn't quite make sense here. Settings is a React component that renders an image, but it's also an object which you instantiate by calling new Settings(). If there are other components which depend on the value of flag, you might want to separate the accessing and storing of the flag from the render component, passing a value and a callback to the renderer.
const Settings = ({setFlag}) => {
return(
<img src="./img/leaf.png" alt="" onClick={() => setFlag(true)}/>
);
}
You've suggested that you like the Context API as a solution for making the flag value globally available. There are a few ways to set this up, but here's one.
Outside of any component, we create a FlagContext object that has two properties: a boolean value flag and callback function setFlag. We need to give it a default fallback value, which is hopefully never used, so our default callback just logs a warning and does nothing.
const FlagContext = createContext<FlagContextState>({
flag: false,
setFlag: () => console.warn("attempted to use FlagContext outside of a valid provider")
});
This FlagContext object gives up Provider and Consumer components, but it's up to us to give a value to the FlagContext.Provider. So we'll create a custom component that handles that part. Our custom FlagProvider uses a local state to create and pass down the value. I've used a function component, but you could use a class component as well.
const FlagProvider = ({children}) => {
const [flag, setFlag] = useState(false);
return (
<FlagContext.Provider value={{
flag,
setFlag
}}>
{children}
</FlagContext.Provider>
)
}
We want to put the entire App inside of the FlagProvider so that the whole app has the potential to access flag and setFlag, and the whole app gets the same flag value.
When you want to use the value from the context in a component, you use either the useContext hook or the Consumer component. Either way, I like to creating an aliased name and export that rather than exporting the FlagContext object directly.
export const FlagConsumer = FlagContext.Consumer;
export const useFlagContext = () => useContext(FlagContext);
With the Consumer, the child of the consumer is a function that takes the value of the context, which in out case is an object with properties flag and setFlag, and returns some JSX.
This is usually a function you define inline:
const SomePage = () => {
return (
<FlagConsumer>
{({flag, setFlag}) => (<div>Flag Value is {flag.toString()}</div>)}
</FlagConsumer>
)
}
But it can also be a function component. Note that when using a function component as the child, you must pass the component itself ({Settings}) rather than an executed version of it (<Settings />).
const Settings = ({ setFlag }) => {
return <img src="./img/leaf.png" alt="" onClick={() => setFlag(true)} />;
};
const SomePage = () => {
return <FlagConsumer>{Settings}</FlagConsumer>;
};
The preferred method nowadays is with hooks. We call useFlagContext() inside the body of the function component and it returns our context object.
const SomePage = () => {
const {flag, setFlag} = useFlagContext();
return <Settings setFlag={setFlag}/>
};
Both the consumer and the hook only work if they are inside of a flag context provider, so that's why we put it around the whole app!
const App = () => {
return (
<FlagProvider>
<SomePage />
</FlagProvider>
);
};
Complete example on CodeSandbox
For this kind of interactions, I highly recommend you to use Redux
Another think I'm sure you will benefit from, is switching to hooks and function components: less boilerplate and much flexible code.
Back to the goal, using Redux your code would look similar to this:
const Settings = (props) => {
const dispatch = useDispatch();
const flag = useSelector(state => state.yourStoreObj.flag);
handleClick() {
dispatch(yourCustomAction("UPDATE_FLAG", true));
}
return(
<img src="./img/leaf.png" alt="" onClick={() => handleClick()}/>
);
}
Explanation:
First of all, spend 15 mins and get used to React Redux. Here's a good practical article to start with. If you're not familiar with hooks, start learning them as that will change a lot, while you don't need to change a single line of what you've done so far.
We suppose there's a property in the store that is the "flag" property of that specific element. In this way, the property can be read by the component itself with the useSelector() operator, or can be read anywhere in your application with the same methodology from any other component.
In the same way, you can change the value by dispatching a change (see dispatch() function) and in the same way, you can do that from any other components.
So, let's say you want to change that property when a click occurs on a completely different component, this is how the other component may looks like
const OtherCoolComp = (props) => {
const dispatch = useDispatch();
handleClick() {
dispatch(yourCustomAction("UPDATE_FLAG", true));
}
return(
<button onClick={() => handleClick()}>
Click me!
</button>
);
}
So you're dispatching the same action, setting it to the value you prefer, from a component that doesn't know who is displaying that value.