I am trying to do something simple: I want my child component to trigger a function found in my parent component, and I understand the right way is using props.
In the following Codepen you can find an example:
https://codepen.io/akmur/pen/MvXGEG
Basically what I want to achieve is to print "hey" to console.
This is my code:
class Form extends React.Component {
constructor(props){
super(props);
}
onClickAdd(){
this.props.addItem();
}
render(){
return(
<div>
<button onClick={this.onClickAdd}>Add</button>
</div>
)
}
}
class App extends React.Component {
constructor(props){
super(props);
}
addItem(){
console.log('hey');
}
render() {
return (
<div>
<Form addItem={this.addItem} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
Thanks for your help!
You don't need the onClickAdd function. Just call this.props.addItem directly onClick (notice, no parens) that you passed down.
class Form extends React.Component {
constructor(props){
super(props);
}
render(){
return(
<div>
<button onClick={this.props.addItem}>Add</button>
</div>
)
}
}
class App extends React.Component {
constructor(props){
super(props);
}
addItem(){
console.log('hey');
}
render() {
return (
<div>
<Form addItem={this.addItem} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
Related
I am doing freecodecamp and I am geting following error:
Uncaught TypeError: Super expression must either be null or a function
I can't figure out where my mistake is. Here is code:
class MyComponent extends React.component{
constructor(props){
super(props);
};
render(){
return(
<div>
<h1>My First React Component!</h1>
</div>
);
};
};
ReactDOM.render(<MyComponent />,document.getElementById('challenge-node'));
it should be React.Component and not React.component
class MyComponent extends React.Component{
constructor(props){
super(props);
};
render(){
return(
<div>
<h1>My First React Component!</h1>
</div>
);
};
};
ReactDOM.render(<MyComponent />,document.getElementById('challenge-node'));
I believe it is because of a simple typo in your code.
You have inputted React.component where is should be React.Component. I rectified that and the code works now.
class App extends React.Component {
render() {
return (
<div>
<h1>My First React Component!</h1>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("challenge-node"));
function Welcome(props) {
console.log("Welcome Back");
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
<Welcome />
}
render(){
return (
<div>
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
Why function handleClick can't call outer function Welcome? is there any solution to this?
To call that function, you should do as follows:
function welcome(props) {
console.log("Welcome Back");
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
}
render(){
return (
<div>
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
Notice that I've lowercased your Welcome function since Pacalcased function names should be reserved for React Components as a general naming convention.
If your intention is to have Welcome be a React component, then it should return some JSX and then you should render that out inside of the render function of your class component:
function Welcome(props) {
return (<div>Welcome Back!</div>
}
class App extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
welcome()
}
render(){
return (
<div>
<Welcome />
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
If you'd like to hide your welcome message until you click the button, you can use state:
function Welcome(props) {
return (<div>Welcome Back!</div>
}
class App extends React.Component {
constructor(props){
super(props);
this.state = {
showWelcomeMessage: false
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
this.setState({showWelcomeMessage: true})
}
render(){
return (
<div>
{this.state.showWelcomeMessage ? <Welcome /> : null}
<button onClick={this.handleClick}>CLICK HERE </button>
</div>
);
}
}
In your example changing <Welcome /> to Welcome() is enough. But you should use camelCase to define functions. But here is the refactored version.
import React from "react";
const welcome = () => {
console.log("Welcome Back");
};
export default function App() {
const handleClick = () => {
welcome();
};
return (
<div>
<button onClick={handleClick}>CLICK HERE </button>
</div>
);
}
Just change the calling of the outer function "Welcome", because it is not a Component:
handleClick(){
Welcome()
}
I'm working on a project using React where I need to update the state of the Parent Component with the Child Component's input. I did console.log() my way through each function in the chain and found that the fetchText() function in my parent component didn't receive the text
Here's what my parent component looks like
class AppComponent extends React.Component{
constructor(props){
super(props);
this.state = { markdownText: `` };
this.fetchText = this.fetchText.bind(this);
}
fetchText(text){
this.setState({ markdownText: text });
console.log(text);
}
render(){
return(
<div id="app-grid">
<h1>Markdown Viewer</h1>
<MarkDownComponent userInput={this.fetchText} />
<PreviewComponent />
</div>
);
}
}
My Child Component looks like this
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
this.sendInput = this.sendInput.bind(this);
}
getInput(event){
this.setState({ text: event.target.value });
this.sendInput();
}
sendInput(){
this.props.userInput = this.state.text;
//console.log(this.props.userInput);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
When console.log()ing this.props.userInput in the Child Component I get the value back as I type. So that indicates the value is making it to the property, but why isn't it updating in the parent component?
Few things to note here:
you cannot change the value of props, it is passed to the component through it parent
this.props.userInput = this.state.text;
this won't work.
So, to make fetchData of parent get the text from textarea you should do like this
<textarea id="editor" rows="16" onChange={this.props.userInput}></textarea>
and in parent component :
fetchText(event){
console.log(event.target.value)
this.setState({ markdownText: event.target.value });
}
you don't require functions like getInput and sendInput to send data to the parent component.
The issue is you are assigning state value to a function which is not correct.
this.props.userInput = this.state.text; // this is incorrect
//Right one
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
this.sendInput = this.sendInput.bind(this);
}
getInput(event){
this.setState({ text: event.target.value });
this.sendInput();
}
sendInput(){
this.props.userInput(this.state.text);
//console.log(this.props.userInput);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
You can directly call this.props.userInput function in getInput function:
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
this.getInput = this.getInput.bind(this);
}
getInput(event){
this.props.userInput(event.target.value);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
ES6 way:
class MarkDownComponent extends React.Component{
constructor(props){
super(props);
this.state = { text: ``};
}
getInput = (event) => {
this.props.userInput(this.state.text);
}
render(){
return(
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={this.getInput}></textarea>
</div>
);
}
}
As told in the comments, there is no need to assign a state to your function. Also, if your desire is to change the text with a Child and nothing more you don't need a state in your Child. Don't use state if it is not necessary.
class AppComponent extends React.Component {
constructor(props) {
super(props);
this.state = { markdownText: "" };
this.fetchText = this.fetchText.bind(this);
}
fetchText(e) {
this.setState({ markdownText: e.target.value});
}
render() {
return (
<div id="app-grid">
<h1>Markdown Viewer</h1>
Value is now: {this.state.markdownText}
<MarkDownComponent userInput={this.fetchText} />
</div>
);
}
}
const MarkDownComponent = ( props ) => {
return (
<div id="markdown-component">
<textarea id="editor" rows="16" onChange={props.userInput}></textarea>
</div>
)
}
ReactDOM.render(<AppComponent />, document.getElementById("root"));
<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>
<div id="root"></div>
i'm using ReactJS without FLux or Redux. I want the grand child component can communicate (read/update data) with his grandparents component.
Here's the parent component App:
export default class App extends React.Component {
static propTypes = {
children: React.PropTypes.object.isRequired
};
constructor(props) {
super(props);
this.state = {
tabActive: 0,
};
}
setTabActive(item) {
this.setState({
tabActive: item,
});
}
render() {
return (
<div>
<Header tabActive={this.state.tabActive} />
<Content>
{this.props.children}
</ Content>
<Footer />
</div>
);
}
}
child component Header:
export default class Header extends React.Component {
render() {
return (
<div>
....
<SettingTabBar tabActive={this.props.tabActive} />
</div>
);
}
}
Child of child component SettingTabBar:
export default class SettingTabBar extends React.Component {
constructor(props) {
super(props);
this.state = { activeTab: this.props.tabActive };
}
render() {
if (location.pathname.indexOf('setting') > 0) {
return (
<Tabs activeTab={this.state.activeTab} onChange={tabId => this.setState({ activeTab: tabId })} ripple>
<Tab>SETTING</Tab>
<Tab>CHARTS</Tab>
<Tab>HELP</Tab>
</Tabs>
);
}
return null;
}
}
Are there anyway to make SettingTabBar component can update data to App/Header component via function setTabActive() when onChange?
For communication with grandparent and grandchild, you can use context. It's not recomended, but it's working.
// root component
class App extends React.Component {
constructor(props){
super(props);
this.state = {
activeMenu: "none"
};
}
getChildContext() {
return {
rootCallback: menuName => {
this.setState({activeMenu: menuName});
}
}
}
render() {
return (
<div>
<div>Current active menu is: <strong>{this.state.activeMenu}</strong></div>
<Child />
</div>
);
}
}
// declare childContextTypes at context provider
App.childContextTypes = {
rootCallback: React.PropTypes.function
}
// intermediate child
class Child extends React.Component {
render() {
return (
<div>
<GrandChild />
</div>
);
}
}
// grand child
class GrandChild extends React.Component {
render() {
return (
<div>
{/* get context by using this.context */}
<button
type="button"
onClick={()=>this.context.rootCallback("one")}
>
Activate menu one
</button>
<button
type="button"
onClick={()=>this.context.rootCallback("two")}
>
Activate menu two
</button>
<button
type="button"
onClick={()=>this.context.rootCallback("three")}
>
Activate menu three
</button>
</div>
)
}
}
// also declare contextTypes at context consumer
GrandChild.contextTypes = {
rootCallback: React.PropTypes.function
}
// render it to DOM
ReactDOM.render(<App /> , document.getElementById('app-mount'));
<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>
<div id="app-mount"></div>
I dont know what i am doing wrong in this code, the prop value 'number' is not updating on front end , although in the console logs it value does get increament.
import React from 'react';
import { render } from 'react-dom';
class Parent extends React.Component{
constructor(props){
super(props);
this.number=0;
this.changeValue=this.changeValue.bind(this);
}
changeValue(){
console.log('-------------this.number',this.number);
this.number=this.number+1;
}
render(){
return(
<div>
<Child callMe={this.changeValue} increaseNo={this.number}></Child>
</div>
)
}
}
class Child extends React.Component{
render(){
return(
<div>
<button onClick={this.props.callMe}>CLick Me</button>
<h1>{this.props.increaseNo}</h1>
</div>
)
}
}
render(<Parent/> , document.getElementById('root'));
You have to store this.number inside the component state, the component will only be re-rendered if its state changes or it receives new props.
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {
number: 0
}
this.changeValue=this.changeValue.bind(this);
}
changeValue(){
this.setState({number: this.state.number + 1});
}
render(){
return(
<div>
<Child callMe={this.changeValue} increaseNo={this.state.number}></Child>
</div>
)
}
}
class Child extends React.Component{
render(){
return(
<div>
<button onClick={this.props.callMe}>CLick Me</button>
<h1>{this.props.increaseNo}</h1>
</div>
)
}
}
jsfiddle