Very new to React, and coming from a jQuery background, the first thing I want to be able to do is toggle classes.
I understand how I can toggle a class within the same react component like this:
class ButtonParent extends React.Component {
constructor(props) {
super(props)
this.state = {
condition: false
}
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
this.setState({
condition: !this.state.condition
})
}
render() {
return (
<ButtonChild
className={ this.state.condition ? "button toggled" : "button" }
toggleClassName={ this.handleClick }
>
Click me if you dare!
</ButtonChild>
)
}
}
class ButtonChild extends React.Component {
render() {
return (
<div
className={ this.props.className }
onClick={ this.props.toggleClassName }
>
{ this.props.children }
</div>
)
}
}
ReactDOM.render(<ButtonParent />, document.getElementById('app'))
But what if I have a a separate component that I want to use in order to toggle the class of the component? Is there no easy way to do this in React?
Thanks!
Just create an ButtonChild.js file near your ButtonParent.js file and export your component
export default class ButtonChild extends React.Component {
render() {
return (
<div
className={ this.props.className }
onClick={ this.props.toggleClassName }
>
{ this.props.children }
</div>
)
}
}
Import it in you ButtonParent.js file like this
import ButtonChild from './ButtonParent.js'
Related
import React from 'react'
export default () => {
function clickHandler() {
console.log('Button clicked')
}
return (
<div>
<button onClick={clickHandler}>Click</button>
</div>
)
}
In the above code we see that a function has been passed to the onClick.In the same way to the onClick I need to pass a diffrent component which is present in the same src. This component consists of a .js and a .css file.Could you please help me out with it. Thanks in advance
If you don't mind using classes instead of functions, your other component should look like this:
import React from 'react'
class ShowThisAfterClick extends React.Component {
return (
<div>
<p>This is what you want to show</p>
</div>
)
}
export default ShowThisAfterClick
And now you should update the component you've shown:
import React from 'react'
import ShowThisAfterClick from './where/you/put/the/ShowThisAfterClick.js'
class Main extends React.Component {
constructor(props){
super(props)
this.state = { isButtonClicked: false }
this.clickHandler = this.clickhandler.bind(this)
}
clickHandler() {
this.setState({ isButtonClicked: true })
}
render() {
const { isButtonClicked } = this.state
return (
<div>
<button onClick={ this.clickHandler }>Click</button>
{ isButtonClicked ? <ShowThisAfterClick /> : ''}
</div>
)
}
}
export default Main
If you want to keep using functions, then I would kindly suggest to read the manual, it is more than well written.
I saw a few similar questions, but about parent/child elements, i have that kind of node tree:
IndexPage -> Modals -> ClientDetails(it's modal component)
-> Header
I want to call ClientDetails.openModal inside Header, tried many ways like creating refs for ClientDetails in indexPage and then pass indexPage to header like prop, but it's works strange, i see refs of props.IndexPage, but when trying access refs directly it's underfind
class IndexPage extends React.Component {
constructor(props) {
super(props);
this.modals = React.createRef();
}
render() {
return (
<Layout>
<SEO/>
<Header indexPage={this}/>
<Story/>
<Products/>
<Clients/>
<Reviews/>
<Partners/>
<Footer/>
<Modals ref={this.modals} />
</Layout>
)
}
}
class Modals extends React.Component {
constructor(props) {
super(props);
this.clientDetailsRef = React.createRef();
}
render() {
return (
<>
<ThankYou/>
<ContactDetails ref={this.clientDetailsRef}/>
</>
)
}
}
class Header extends React.Component {
constructor(props) {
super(props);
this.state = { isActive: false, isSticky: false };
this.toggle = this.toggle.bind(this);
this.indexPage = props.indexPage
console.log(this.indexPage)
console.log(this.indexPage.modals)
}
}
I think you can solve your problem using react.js context.
You wanted to control the Modals component in the Header component. So you tried to reference the Modals component toggle function in the Header component to solve the problem.
I think it is a fine solution.
But in my opinion, sharing state in peer components is also another solution.
So you can use react.js context to share states between two peer components in a parent component of them. I think doing this is following react declarative programming.
Please check this code
Here is a small fiddle for calling a child function from the parent
https://jsfiddle.net/c1qfn9Lx/9/
class Modal extends React.Component {
constructor(props) {
super(props);
this.state= {
showModal: false
}
this.toggleModal = this.toggleModal.bind(this)
}
toggleModal() {this.setState({showModal: !this.state.showModal})}
render() {
const { showModal } = this.state;
return(
<div className="modal">
{showModal &&
<div>
Showing modal
</div>
}
</div>
)
}
}
class TodoApp extends React.Component {
constructor(props) {
super(props)
this.modalRef = React.createRef()
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.modalRef.current.toggleModal();
}
render() {
return (
<div className="parent">
<Modal ref={this.modalRef} />
<button onClick={this.handleClick}>Click</button>
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
I would try doing this:
class IndexPage extends React.Component {
constructor(props) {
super(props);
this.state = {modalsRef: null};
}
render() {
return (
<Layout>
<SEO/>
<Header modalsRef={this.state.modalsRef}/>
<Story/>
<Products/>
<Clients/>
<Reviews/>
<Partners/>
<Footer/>
<Modals ref={r => !this.state.modalsRef && this.setState({modalsRef:r})} />
</Layout>
)
}
}
But please note: the property won't work in the constructor of Header most likely. It should work though by the time you're doing things like Button.onClick callbacks.
I know that this is probably the most asked question about React, but none of the answers helped me.
I have 2 classes:
Child
class Preview extends Component {
constructor(...args) {
super(...args);
this.state = {
isCommentOpen: false
};
this.handleComment = ::this.handleComment;
render() {
return(
button type="button" onClick={this.handleComment}>Comment</button>
)}
handleComment(){
this.setState({isCommentOpen: !this.state.isCommentOpen});
}
export default Preview;
Parent
class Profile extends Component {
render(){
return(
<div>
<_.Preview />
//the place where I want to add validation from the component above
{this.state.isCommentOpen ? <span>Cool</span> : null}
</div>
}
You should not mutate or directly assign this.props as shown in the other answer:
this.props.isCommentOpen = !this.props.isCommentOpen // <-- DON'T DO THIS! 🎃
Instead, you should have a callback function to let the Parent component update the child component:
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
isCommentOpen: false;
}
this.handleComment = this.handleComment.bind(this); // <-- important!
}
handleComment() {
this.setState({ isCommentOpen: !this.state.isCommentOpen });
}
render() {
return (
<div>
<Preview handleComment={this.handleComment} />
{ this.state.isCommentOpen ? <span>Cool</span> : null }
</div>
)
}
}
export default Profile
The child component then only needs to call this.props.handleComment:
// Child Component:
class Preview extends Component {
render() {
return(
<button type="button" onClick={this.props.handleComment}>Comment</button>
}
}
export default Preview;
How to let func run after Component A constructor in react. When I debugger blow codes, the func be to called first, then the A constructor, but in my case I want to the opposite, how can I do it?
function func() {
return 'aa'
}
class A extends Component {
constructor(props) {
super(props)
}
render() {
return <div>
{this.props.children}
</div>
}
}
class App extends Component {
render() {
return (
<A>
{func()}
</A>
)
}
}
You should do something like this:
class A extends Component {
constructor(props) {
super(props)
}
componentWillMount() {
this.func();
}
func() {
// this will run once when component A runs
}
render() {
return <div>
{this.props.children}
</div>
}
}
class App extends Component {
render() {
return (
<A></A>
)
}
}
This way, when component App runs, it will trigger the componentWillMount method in component A, which will call the func() function.
There are many solutions for this, but I would have done something like this:
function func() {
return 'aa'
}
class A extends Component {
constructor(props) {
super(props)
}
render() {
return( <div>
{typeof this.props.children === 'function' ? this.props.children() :
this.props.children}
</div>)
}
}
class App extends Component {
render() {
return (
<A>
{func}
</A>
)
}
I made an app with multiple components and want their state to be accessed using parent/main app, I'm not sure how to get it. what i'm trying to do is when i change state in main "App" the component state should change. One of the component is 'checkbox' and now i want to access its state using parent app, I made multiple attempts but not getting it done. my code goes like this..
This is Main 'App' code:
import React, { Component } from 'react';
import Checkbox from './checkbox';
import Radio from './Radio';
import ToggleSwitch from './ToggleSwitch';
import PrimaryButton from './PrimaryButton';
class App extends Component {
onClick(isClicked){
isChecked:true
};
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
/>
<RadioButton
onClick={this.onClick}
/>
</div>
);
}
}
export default App;
The component i want to access goes like this:
import React, { Component } from 'react';
class Checkbox extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
};
};
onCheck(){
this.setState({
isChecked: !this.state.isChecked
});
this.props.isClicked()
};
render() {
return (
<div>
<div
className={this.state.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
);
}
}
export default Checkbox;
You forgot to bind the onClick event in the app component, try this it will work :
class App extends Component {
onClick(isClicked){
console.log('isClicked', isClicked);
};
render() {
return (
<div id="form">
<Checkbox onClick={this.onClick.bind(this)}/>
</div>
);
}
}
If you already have onClick handler for the Checkbox I don't see why you couldn't just move the state up to the App component and just pass down a callback from there to the Checkbox that will update the parent state. That seems like a more React way to do it, to me.
class App extends Component {
constructor(props){
super(props);
this.state={
isChecked:true
}
}
onClick = (isClicked) => {
this.setState({isChecked: !this.state.isChecked})
}
render() {
return (
<div id="form">
<Checkbox
onClick={this.onClick}
ischecked={this.state.isChecked}
/>
</div>
);
}
}
Component
class Checkbox extends Component {
onCheck(){
this.props.onClick()
}
render() {
return (
<div>
<div
className={this.props.isChecked ? 'checked': 'unchecked'}
onClick={this.onCheck.bind(this)}
>
</div>
</div>
)
}
}