(React + Meteor) Edit content in another div? - javascript

I currently have this as my "index" for my Meteor app:
import React from 'react';
export const App = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired,
},
render() {
return <div className="app-div">
**<Foo/>**
**<Bar/>**
{ this.props.children }
</div>;
},
});
I am wondering if I can somehow change content of "Foo", through code in "Bar".
Essentially, "Foo" will have code like this:
export class Foo extends React.Component {
render() {
return(
<div className="test">TEXT TO BE REPLACED</div>
);
}
}
Bar, will also have similar code:
export class Bar extends React.Component {
render() {
// Code goes here to change that div "test"'s content in Foo^^^^^^
return(
<div>...</div>
);
}
}
But I need to have some sort of code that changes the "TEXT TO BE REPLACED". Is there a way to do this somehow? Maybe with the react DOM or something? I am kind of brute forcing my way through this, so I may not know basic fundamentals, sorry
Thanks in advance

In React+Meteor, communication between two siblings component should be done through their parent.
For your case, I would use a state in App component to store the content of "TEXT TO BE REPLACE", and a function inside App component to update that state content:
import React from 'react';
export const App = React.createClass({
propTypes: {
children: React.PropTypes.element.isRequired,
},
getInitialState() {
return {
fooText: '',
};
},
updateFooText(value) {
this.setState({
fooText: value,
});
},
render() {
return (
<div className="app-div">
<Foo text={this.state.fooText} />
<Bar updateFooText={this.updateFooText} />
{ this.props.children }
</div>
);
},
});
export class Foo extends React.Component {
render() {
return (
<div className="test">{this.props.text}</div>
);
}
}
export class Bar extends React.Component {
onChangeHandler(e) {
this.props.updateFooText(e.target.value);
},
render() {
// Code goes here to change that div "test"'s content in Foo^^^^^^
return (
<div>
<input type="text" onChange={this.onChangeHandler} />
</div>
);
}
}

Related

How to pass component to onClick in react

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.

Passing state from child class to parent

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;

React JS - Passing functions for child components

I have an App component and a function 'modalToggled' inside its.
I want to pass the function to multiple child components until I get to the last one, the 'interiores' component.
Like this:
<App> -> <Coluna1> -> <MenuPrincipal> -> <Portfolio> -> <PortfolioMenu> -> <interiores>
App Component, the parent of all components:
import React, { Component } from 'react';
import Coluna1 from './Coluna1'
class App extends Component {
constructor(props) {
super(props)
this.state = {
modalOn: false
}
this.modalToggled = this.modalToggled.bind(this)
}
modalToggled = (on) => {
this.setState({modalOn: on});
}
render() {
return (
<div>
<Coluna1 onModalToggle={this.modalToggled}/>
</div>
)
}
}
export default App;
This is the 'Coluna1' the first child component. I did the same thing in the another ones: 'MenuPrincipal', 'Portfolio', 'PortfolioMenu'
class Coluna1 extends Component {
constructor(props){
super(props)
}
render() {
return (
<div>
<Header />
<MenuPrincipal onModalToggle={this.props.modalToggled} />
</div>
)
}
}
export default Coluna1
Therefore here is the last component interiores, when I click on the button there appears an error message:
TypeError: _this.props.onModalToggle is not a function
import React, { Component } from 'react'
import Modal from 'react-responsive-modal';
class Interiores extends Component {
constructor(props) {
super(props)
this.state = {
open: false
}
}
onOpenModal = () => {
this.setState({ open: true });
this.props.onModalToggle(true);
};
onCloseModal = () => {
this.setState({ open: false });
this.props.onModalToggle(false);
};
render() {
const { open } = this.state;
return (
<div>
<button onClick={this.onOpenModal}>Open modal</button>
<Modal open={open} onClose={this.onCloseModal} center></Modal>
</div>
)
}
}
export default Interiores;
Does anybody know how to solve it? Thank you
It happens, because in App class you pass prop with name onModalToggle:
<Coluna1 onModalToggle={this.modalToggled}/>
But in Coluna1 you receive this props with wrong name, modalToggled:
<MenuPrincipal onModalToggle={this.props.modalToggled} />
Just make the names of props equal. In Coluna1 and other intermediate components pass and receive this props as onModalToggle:
<MenuPrincipal onModalToggle={this.props.onModalToggle} />
This is the problem
modalToggled = (on) => {
this.setState({modalOn: on});
}
Since this is a class function it needs to be defined like
modalToggled(on) {
this.setState({modalOn: on});
}

ReactJS How to pass child component values to parent component

I have below codes
chat.js
import React from 'react';
import '../styles/Chat.css';
import Web from '../services/Web';
class Chat extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:''
};
this.sendMessage = this.sendMessage.bind(this);
}
sendMessage () {
this.props.updatecommentText(this.refs.newText.value, this.props.index);
this.setState({ msg: '' });
}
render() {
return (
<div className="Chat-container">
<div className="Chat-row">
<div className="Chat-column">
<div className="Chat-card">
<div className="Chat-body">
<div className="Chat-title">React Based Chatbot</div>
<div className="Chat-messages">
{ this.props.children }
</div>
</div>
<div className="Chat-footer">
<textarea className="Chat-input" ref="newText"></textarea>
<button className="Chat-submit" onClick={this.sendMessage} defaultValue={ this.props.children }>Send</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Chat;
Web.js
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import Chat from '../components/Chat';
class Web extends React.Component {
constructor(props){
super(props);
this.state = {
messages:["Hi, How can I help you ?"
]
};
this.sendtobot = this.sendtobot.bind(this);
}
sendtobot(newText, i){
var arr = this.state.messages
arr.push(newText)
this.setState({messages: arr})
}
eachMessage(message, i){
return (<Chat key={i} index={i} updatecommentText={ this.sendtobot.bind(this) }>{ message }</Chat>);
}
render(){
return(
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
</div>
)
}
}
export default Web;
I wanted to take the input from the Chat.js and send it to Web.js and push that value to array messages and then again render that array in the this.props.children in Chat.js
But, while running the code, I am getting an error this.props.updatecommentText is not a function.
Can someone please help me with this.
You have bind this.sendtobot twice. It should be only in the constructor.
like this
eachMessage(message, i){
return (
<Chat key={i} index={i} updatecommentText={this.sendtobot}>
{ message }
</Chat>
);
}
Your code seems to work.
Here is a sandbox with your code.
I'm not sure it works as you would expect, but it works without errors.
By changing this 3 functions in Web component, it starting to look like a chat with only one textarea
sendtobot(newText, i) {
this.setState({ messages: [...this.state.messages, newText] })
}
eachMessage(message, i) {
return (<p>{message}</p>);
}
render() {
return (
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
<Chat updatecommentText={this.sendtobot}/>
</div>
)
}
You can pass child's component state to parent component using redux also as global state.

How to modify child Component content?

I have a Component like this:
<MyTimer props={+new Date()}>
<span className="year" formatter="yyyy" />
<span className="mon" formatter="mm" />
<span className="day" formatter="dd" />
</MyTimer>
MyTimer is Component like this(I just ignore some other code):
render() {
/**
* this code may not work, I just do what I think.
*/
return (<div>
{ this.props.children.map((child, i) =>
// child.children=[util.date(child.formatter)])
// set child.props.children as "util.date(child.formatter)"
}
</div>)
}
I want to change the content of span in component, which should result like this:
<span class="year">2016</span>
<span class="mon">07</span>
<span class="day">06</span>
So why do I need this, because I can change the child element type as I like:
<MyTimer props={+new Date()}>
<div className="year" formatter="yyyy" />
<span className="mon" formatter="mm" />
<p className="day" formatter="dd" />
</MyTimer>
I just do not care about what the child element is, and also className.
React has a feature called "contexts", which allow a parent component to implicitly pass some data to children.
The actual formatting then can happen in a special "formatter" component. Resulting in something like this:
import React, { Component, PropTypes } from 'react';
import moment from 'moment';
class MyTimer extends Component {
static childContextTypes = {
date: PropTypes.object
};
// expose some props to children
getChildContext() {
return {
date: this.props.date
};
}
render() {
return <div>{this.props.children}</div>;
}
}
class TimerPart extends Component {
// this is REQUIRED to receive the date from the parent
static contextTypes = {
date: PropTypes.object
};
render() {
// use it like `this.context.date`
return <span>{moment(this.context.date).format(this.props.format)}</span>;
}
}
export default class App extends Component {
render() {
return (
<MyTimer date={new Date()}>
<TimerPart format="YYYY"/>
<TimerPart format="MM"/>
<TimerPart format="DD"/>
</MyTimer>
)
}
}

Categories

Resources