ReactJs Calling parent function - reactjs

I am sorry if it is duplicate. I am passing parent function to child but when I use this method in child it give me this error
_this2.props.changeAppMode is not a function
I tried stackover flow already answered questions but can't able to resolve it. I am a newbie so might be I am missing some other concept
Following are my components
Parent Component
class Users extends React.Component {
constructor(props) {
super(props);
this.state = {
currentMode: 'read',
userId: null
};
this.changeAppMode = this.changeAppMode.bind(this);
}
changeAppMode(newMode, userId) {
this.setState({currentMode: newMode});
if (userId !== undefined) {
this.setState({userId: userId});
}
}
render() {
var modeComponent =
<ReadUserComponent
changeAppMode={this.changeAppMode}/>;
switch (this.state.currentMode) {
case 'read':
break;
case 'readOne':
modeComponent = <ViewUser />;
break;
default:
break;
}
return modeComponent;
}
}
export default Users;
Child
class ReadUserComponent extends React.Component {
constructor(props) {
super(props);
console.log(props);
};
componentDidMount() {
this.props.fetchUsers();
}
render(){
const users = this.props.users;
return (
<div className='overflow-hidden'>
<h1>Users List </h1>
<TopActionsComponent changeAppMode={this.props.changeAppMode} />
<UsersTable
users={users}
changeAppMode={this.props.changeAppMode} />
</div>
);
}
}
ReadUserComponent.propTypes = {
users: React.PropTypes.array.isRequired,
fetchUsers: React.PropTypes.func.isRequired
}
function mapStateToProps(state) {
return {
users: state.users
}
}
export default connect(mapStateToProps, { fetchUsers })(ReadUserComponent);
Child of Child [This component calling parent function]
class TopActionsComponent extends React.Component {
render() {
return (
<div>
<a href='#'
onClick={() => this.props.changeAppMode('create')}
className='btn btn-primary margin-bottom-1em'> Create product
</a>
</div>
);
}
}
export default TopActionsComponent;
Thanking you in anticipation. Really appreciate your help
Sorry if it is duplicate but I am kind of a stuck in it

I think it's related to binding in child component. Could you try below piece of code while passing props into child component.
<TopActionsComponent changeAppMode={::this.props.changeAppMode} />

okay. try this. I think it should work.
<ReadUserComponent changeAppMode={() => this.changeAppMode}/>;
<UsersTable
users={users}
changeAppMode={() => this.props.changeAppMode} />

Try this, it solved the same issue i was facing.
In ReadUserComponent Component:
<TopActionsComponent changeAppMode={this.changeAppMode.bind(this)} />
Define this function in ReadUserComponent:
changeAppMode(type){
this.props.changeAppMode(type);
}
In TopActionsComponent Component:
<a href='#' onClick={this.changeAppMode.bind(this,'create')}
className='btn btn-primary margin-bottom-1em'> Create product
</a>
Define this function in TopActionsComponent Component:
changeAppMode(type){
this.props.changeAppMode(type);
}

Related

Child not updating after Parent State changed

I am quite new with React and I have problem bellow
I have a parent component like this:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {count:1};
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
return false;
}
setCount = () => {
this.setState({
count: 2
});
};
render() {
const {name, running, onRun, onStop} = this.props;
return (
<div>
<Test count={this.state.count}/>
<p><a href="#" onClick={this.setCount}>SetCount</a></p>
</div>
);
}
}
And here is Test component
class Test extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
return true;
}
render() {
const {count} = this.props;
return (
<div>
{console.log("Counting")}
<p>{count}</p>
</div>
);
}
}
I have method "shouldComponentUpdate" returns "false" in Parent component because I don't want to re-render it.
My understanding is React know which part of DOM need to be re-rendered. And in this case, the state of Parent changes will re-render "Test" component
But when I run above code, "Test" component does not redender.
Is there anything wrong in my code?
Thanks a lot for your help
You need to return true from your parent's shouldComponentUpdate method.
If you return false, after the initial render it won't update, even if you call a function that calls setState.
Is the refresh of the whole page are you talking about? If thats the case, probably you wanna change your <a> tag to button or use e.preventDefault();.
If not, I am not sure if that is possible. If you setState in the parent, it will rerender parent as well as the children. If you dont want to render the parent then you have to manage individual state management in the child level.
For example,
class Parent extends React.Component {
constructor(props) {
super(props);
}
render() {
const {name, running, onRun, onStop} = this.props;
return (
<div>
<Test/>
</div>
);
}
}
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {count:1};
}
setCount = (e) => {
e.preventDefault();
this.setState({
count: 2
});
};
render() {
const {count} = this.state;
return (
<div>
{console.log("Counting")}
<p>{count}</p>
<p><a href="#" onClick={this.setCount}>SetCount</a></p>
</div>
);
}
}

Child component's state does not change while rendering

I am a novice to ReactJs so please bear with me. I am trying to build a project from this course called Git-Hub profile viewer. Here is my code for Parent component:
import Profile from './github/Profile.jsx';
class App extends Component {
constructor(props){
super(props);
this.state = {
username: 'xxxx',
userData: [],
userRepos: [],
perPage: 5
}
}
// get user data from github
getUserData(){
$.ajax({
url: 'https://api.github.com/users/' +this.state.username+'?client_id='+this.props.clientId+'&client_secret='+this.props.clientSecret,
dataType:'json',
cache:false,
success: function(data){
this.setState({userData:data});
console.log(data);
}.bind(this),
error: function(xhr, status, err){
this.setState({userData: null});
alert(err);
}.bind(this)
});
}
componentDidMount(){
this.getUserData();
}
render(){
return (
<div>
<Profile userData = {this.state.userData} />
</div>
)
}
}
App.propTypes = {
clientId: React.PropTypes.string,
clientSecret: React.PropTypes.string
};
App.defaultProps = {
clientId: 'some_genuine_client_Id',
clientSecret:'some_really_client_secret'
}
export default App;
and here is my child's component:
class Profile extends Component {
render() {
return (
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">{this.props.userData.name}</h3>
</div>
<div className="panel-body">
</div>
</div>
)
}
}
export default Profile;
Problem is that the props in child component does not update its state while rendering the page although the data retrieval is successful from Git-Hub as shown in console log. What am I doing wrong, can somebody please help?
So firstly, you should be ensuring that you are accessing userData in the correct way, as #mersocarlin mentioned. This is quite likely to be the cause of your problem.
Theoretically, your way of doing this should work. However I've written a working jsfiddle for you as an example. I couldn't make the Ajax call so have simulated it with a setTimeout event over 5 seconds.
The other way of doing this is to pass down the getUserData function to the child component (Profile) and let it handle the call itself. Here is the jsfiddle for that, and the code below:
class Profile extends React.Component {
constructor(props) {
super(props);
this.state = {
userData: {}
};
}
componentDidMount() {
const userData = this.props.getUserData();
console.log(userData);
this.setState({ userData: userData });
}
render() {
return (
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">Hello, {this.state.userData.name || 'World'}</h3>
</div>
<div className="panel-body">
</div>
</div>
)
}
}
class App extends React.Component {
getUserData(){
return {
'name': 'Tom'
}
}
render(){
return (
<Profile getUserData={this.getUserData} />
)
}
};
First of all, you should call getUserData() in componentWillMount rather than componentDidMount to get the data before the component has rendered. And then in the child component use a life cycle method componentWillReceiveProps to check if the child component is getting the right props and updating the state accordingly. It'll be something like this:
componentWillReceiveProps(nextProps) {
if(this.props.userData !== nextProps.userData) {
console.log('condition met');
this.setState({
userData: nextProps.userData
});
}
}
Try this and let me know, I'll help you further.

React Smart and Dumb Components

Have been working on React and would like to know, best practices for seperating smart and dumb componenents. Example below Parent controls state, but i have put button ui in render, should these go into child and implemented back to parent via callback or is that overkill? thoughts..here is my code
class Child extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<div><p>I said {this.props.greeting} {this.props.count} times</p>
</div>
);
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
count: 0,
greeting: "Hello"
};
}
sayHello() {
this.setState((prevState, props) => {
return {
count: prevState.count + 1,
greeting: "Hello"
}
}
)};
sayGoodBye() {
this.setState((prevState, props) => {
return {
count: this.count = 1,
greeting: "Goodbye"
}
}
)};
render() {
return (
<div>
<button onClick={() => this.sayHello() }>Say Hello</button>
<button onClick={() => this.sayGoodBye() }>Say Goodbye</button>
<Child count={this.state.count} greeting={this.state.greeting} />
</div>
)
}
}
ReactDOM.render(<Parent />, document.getElementById('app'));
I think the separation in this case is good. The buttons are directly involved with the state of Parent so creating a child just for them will be an overkill. In general the "dump" components are only about visually showing data/state. Sometimes they contain elements like buttons but the only one thing that they do is to notify the outside world that X thing happened.
Also the Child could be a stateless function:
const Child = ({ greeting, count }) => (
<div>
<p>I said { greeting } { count } times</p>
</div>
);
You could try making a component to be just a function. If you can't then it is probably not as dump as you think it is :)

Reactjs this.setState is not a function error

Im novice to React js, i don't know whats wrong with below code, but i'm getting setState is not a function error.Please help me to fix this.
class AppBarLayout extends React.Component {
constructor(props) {
super(props);
this.state = {
visibleSideBar:true,
slide:""
}
}
showProfile(){
this.setState({
slide:'slide'
});
console.log(this.state.slide);
}
render(){
return(
<div>
<header>
<NavBar show={this.showProfile}/>
<Profile slide={this.state.slide} />
</header>
</div>
);
}
}
export default AppBarLayout;
You need to bind this.showProfile in the component constructor
this.showProfile = this.showProfile.bind(this)
More detail about this on the Handling Events page of the React doc : https://facebook.github.io/react/docs/handling-events.html
Expanding on Delapouite's answer if you don't like to bind every function in the constructor you can use arrow functions to automatically bind to the correct context.
For example:
class AppBarLayout extends React.Component {
constructor(props) {
super(props);
this.state = {
visibleSideBar:true,
slide:""
}
}
// Now showProfile is an arrow function
showProfile = () => {
this.setState({
slide:'slide'
});
console.log(this.state.slide);
}
render(){
return(
<div>
<header>
<NavBar show={this.showProfile}/>
<Profile slide={this.state.slide}/>
</header>
</div>
);
}
}
export default AppBarLayout;
In my case, I solved the problem without binding.
Declaring the method like this was generating the error:
async onSubmit(e) {
event.preventDefault();
this.setState({ shopEthereumAddress: e.target.id });
}
The CORRECT declaration which will not generate the error is this:
onSubmit = async event => {
event.preventDefault();
this.setState({ shopEthereumAddress: event.target.id });
}
This works.
toggleSwitch() {
this.setState({
name: 'Ram ji'
});
}
Using an arrow function keeps the context of this set to the parent scope. The main benifit of arrow functions apart from being more concise is
Main benefit: No binding of ‘this’
// use this arrow function instead of
toggleSwitch = () => {
this.setState({
name: 'Ram ji' //It's working
});
}

How to share a property with React components?

I'm new to React and I have a question about sharing properties from one component to another. For example, I want a parent component that has a "visible" function that I can pass to other child components.
Example:
CustomInput visible="true";
CustomDropDown visible="false"
I'd like to know the best way to do this, respecting good practices. Thank you for your help!
Real simple. You can pass methods as props. Suppose you have a parent, or Higher Order Component (HOC), you could do something like this:
class Parent extends React.Component {
logWord = (word) => {
console.log(word);
}
render () {
return <ChildComponent handleLogging={ this.logWord } />
}
}
Then, in the ChildComponent, you simply access the method from props. For instance:
class ChildComponent extends React.Component {
render () {
return (
<div onClick={ this.props.handleLog.bind(null, 'Logged!') }>Click me to log a word!</div>
}
}
}
So, in your example, if you wanted a method that existed on the parent that updated a visibility attribute on your state, you could write:
class Parent extends React.Component {
constructor () {
this.state = {
visible: false
}
}
setVisible = (bool) => {
this.setState({ visible: bool });
}
render () {
return <ChildComponent updateVisible={ this.setVisible } visible={ this.state.visible } />;
}
}
ChildComponent:
class ChildComponent extends React.Component {
render () {
return (
<div>
<div onClick={ this.props.updateVisible.bind(null, true) }>Set me to visible!</div>
<div onClick={ this.props.updateVisible.bind(null, false) }>Set me to invisible!</div>
{ this.props.visible && <div>I'm visible right now!</div> }
</div>
}
}
}

Resources