I have a class extending a custom component which extends another custom component. I want to override handleReload() function to add some extra functionality. I don't want to completely change it's behavior. The problem is that I get errors even when the page loads, and it lacks any functionality.
To sum it up a little bit, there are 3 layers of components, parent -> child -> grandchild, handleReload() is declared in child.
export default class Child extends Parent {
handleReload() {
return () => {
const { name, load } = this.props
load(name)
}
}
<ReloadButton
value={'action.reload'}
onClick={::this.handleReload()}
privilege={`${metaForm(name)}:Read`}
/>
}
Now what I am trying to do is something like this:
export class GrandChild extends Child {
handleReload() {
super.handleReload()
// something else here
}
}
You would need to evaluate something in handleReload to tell it whether it's coming from a grandChild or not and then use a if statement of some sort to do this or that.
// ----- parent.js
export class ParentContainer extends Component {
import {GrandChild} from './components/grandchild';
handleReload = type => {
if(type === 'grandchild'){
// something
} else {
// something else
}
}
render() {
return (
<GrandChild onReload={this.handleReload} />
)
}
}
Example of passing it back in props
// / ----- /components/grandchild.js
export class GrandChild extends Component {
render() {
return (
<button onClick={this.props.onReload('grandchild')}
);
}
}
Related
Lets say I have a component defined like this -
// actioncomponent.js
import React from 'react';
class ActionComponent extends React.Component {
state = {
isAction: false;
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
Some render stuff..
</div>
)
}
}
export default ActionComponent
From another completely different file I want to set the state for the first component without rendering it in the new file so I need not use refs or props.
// newfile.js
import ActionComponent from './actioncomponent.js'
ActionComponent.doAction()
I'm aware the doAction can't be exported and calling it static doesn't have access to state either. How do I achieve something like this?
In React ecosystem you probably don't need this.
You can pass this method to a child component:
class ActionComponent extends React.Component {
state = {
isAction: false
}
doAction = () => {
this.setState({isAction: true})
}
render () {
return (
<div>
<Child doAction={this.doAction} />
</div>
)
}
}
And then in a Child component you can fire this action
// ...
render() {
<button onClick={() => props.doAction()}>Test</button>
}
If you need to fire action on parent, instead of child you might want to structure your state on upper level, or lift state up.
You can also achieve similar goal without drilling props, but you'll need some state management tool, e.g. Redux or in some cases Context API would be a great fit.
I have a parent component which contains a function, which when called needs to acces the childrenĀ“s component state. I dont want to move the whole state to the parent component because i want the children component to be independent. What is the cleanest and most recommended way to achieve this?
class ParentComponent extends Component {
render() {
return (
<div>
<ChildComponent/>
<SaveButton onClick={this.saveFunction}/>
</div>
)
}
saveFunction = () => {
//Here i need to acces the child Component state
}
}
My solution so far was that everytime something changed in child component i called a function which was passed from the parent Component. Like this:
class ChildrenComponent extends Component {
state = {
name: "David",
age: 19
}
render() {
return (
//inputs with the inputChange function
)
}
inputChange = (e) => {
//Update the state
//Then pass the state to the parent
this.props.passStateToParent(this.state)
}
}
I would recommend to look up some of the React patterns - especially Render Props, as it allows to expose the state and wanted methods of a component - what you want in this situation.
Best of luck!
You can make a function in parent component and pass it down to child component as prop. This function could return to parent component the state of your child component. See more here: https://reactjs.org/docs/faq-functions.html
You cannot directly access the state of the child component,this can be done by passing the state to methods of parent component which are passed as props to child component,the following example demonstrate how to do it .
class ParentComponent extends React.Component {
somefunc() {
//do your action
}
render() {
<ChildComponent parentfunc={this.somefunc}/>
}
}
class ChildComponent extends React.Component {
constructor(props){
super(props)
this.state = {somedate:'value'}
this.func = this.func.bind(this)
}
func() {
this.props.parentfunc(this.state)
}
render() {
<button onClick={this.func}>text</button>
}
}
I am having a child component a parent component. I am having a function in child component which returns some jsx what i want to do is use that function to return the same jsx in parent component but iam unable to figure out a way to do that. I am giving my minimal code:
parent component:
class App extends Component {
render() {
return (
<div className="App">
<Player ref={instance=>{this.player = instance}} />
{this.player.func('aaa.com','bbb')}
</div>
);
}
}
export default App;
Child component:
import React, { Component } from "react";
class Player extends Component {
func = (url, label) => {
return (
<button onClick={() => this.func(url)}>
{label}
</button>
)
}
render() {
return <div>1</div>;
}
}
export default Player;
Error: Cannot read property 'func' of undefined
//
Note: i know i can use the jsx in parent component by copy-pasting but iam trying to figure out a way of doing like this. I am having doubt that is it even possible
You can create a Player object and access the function using that object.
new Player().func('aaa.com','bbb')
I don't quite understand what you need exactly but I think that you're looking to pass some jsx element from the Child component to the parent component. What we can do is declare a propType callback on the child component and then implement it on the parent component like so.
import React from 'react';
class Hello extends React.Component {
constructor() {
super();
this.state = {
// this state will keep the element returned by the parent
returnElements: null
}
this.onReturn = this.onReturn.bind(this);
}
// this method will be fired when the Child component returns callback for onSomethingReturned
onReturn(element) {
this.setState({
returnElements: element
})
}
render () {
return (
<div>
<h1>Hello, React!</h1>
<Child onSomethingReturned={this.onReturn} />
{/* I am going to display the state here */}
{this.state.returnElements}
</div>
)
}
}
class Child extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
const element = <h3>this is child element</h3>;
// will call the propType callback function with a element I want to return
this.props.onSomethingReturned(element);
}
render() {
return (null);
}
}
export default Hello;
I have a dumb component, List, that has some methods defined like this:
class List extends React.Component {
...
scrollTo() {
...
}
clear() {
...
}
}
I then use it in a Parent Component, let's say UsersList:
class UsersList extends React.Component {
render() {
return <List {...this.props} {...} />;
}
}
Then I have as a Parent I have FriendsPage:
class FriendsPage extends React.Component {
render() {
return (
...
<UsersList ref={(ref) => { this.usersListRef = ref; }} {...} />
);
}
}
I'd like to be able to call this.usersListRef.scrollTo() for example in FriendsPage, without having to define the methods of List in UsersList.
I can pass a prop called listRef and use it as ref={this.props.listRef} but I was wondering if another solution exists.
You can't call functions of a child and that would also be against the idea of react. Ideally your <UserList> component accepts a prop that makes it know where to scroll to. Something like:
class UserList extends React.Component {
componentDidUpdate() {
const {activeItem} = this.props;
this.scrollTo(activeItem);
}
scrollTo = activeItem => {
// calculate position of active item to scroll to
// and scroll to it
}
}
And then your <FriendsPage> could look something like this:
class FriendsPage extends React.Component {
handleSelectionChange = selected => {
// triggered when the selected element in the list changes
this.setState({selected});
}
render() {
const {selected} = this.state;
return <UserList activeItem={selected} {...this.props} />;
}
}
It's hard to tell if this is 100% the approach you need as you did not provide many details about the conditions that lead to scrolling.
Mmmm, I'm not sure if I'm getting It right, but you should read this: https://reactjs.org/docs/thinking-in-react.html
In React, the idea is to go top-down. As you need the UsersList component to do something when user interacts with List component, then you should define the function in UsersList and pass that function as a prop to the List Component.
For example:
class List extends React.Component {
<div onClick={this.props.scrollTo}
}
I then use it in a Parent Component, let's say UsersList:
class UsersList extends React.Component {
scrollTo(){
do something...
}
render() {
return <List scrollTo={() => this.scrollTo()} {...this.props} {...} />;
}
}
Then I have as a Parent I have FriendsPage:
class FriendsPage extends React.Component {
render() {
return (
...
<UsersList {...} />
);
}
}
I forgot to check the documentation on this one, and there is a paragraph about it here: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components.
Basically, it is the solution I envisaged in my question, using a listRef and passing it down to wherever my List Component is.
Thanks, everyone!
I am using React v0.14.8. I tried to call the fetchData function from another component. Here is my code:
export default class TagUtils extends React.Component {
deleteTag = () => {
Tags.deleteTag(this.props.tag).then(function(response){
if(response.message === 'tag successfully deleted')
Sidebar.fetchData();
});
}
// other codes
And:
export default class Sidebar extends React.Component {
fetchData() {
Tags.getTags().done((response) => {
this.setState({tags: response.tags || [], loaded: true});
});
}
//other codes
When I called deleteTag, I got this error in my console:
TypeError: _SidebarJsx2.default.fetchData is not a function
You can't call Sidebar.fetchData because fetchData is not a static member of Sidebar, it is an instance member. This means you need an instance of Sidebar to call fetchData on, for example new Sidebar().fetchData(). Of course, this is not how a React component is supposed to be used, and it would not set state on all other Sidebar instances, so it wouldn't be meaningful.
What you want to do is pass a callback to your TagUtils component:
export default class TagUtils extends React.Component {
deleteTag = () => {
Tags.deleteTag(this.props.tag).then((response) => {
if(response.message === 'tag successfully deleted')
this.props.onDeleteTag();
});
}
}
export default class Sidebar extends React.Component {
fetchData() {
Tags.getTags().done((response) => {
this.setState({tags: response.tags || [], loaded: true});
});
}
render() {
return (
{ this.state.tags.map((tag) =>
<TagUtils tag={tag} onDeleteTag={this.fetchData} />) }
);
}
}
If you have to thread this callback through several layers of components that's okay, that's typical in React. However, if you find yourself passing a lot of stuff down props through many component layers that seem out of place, or trying to reconcile changes across large horizontal spaces in your app, this is a primary use-case for things like Flux and Redux.