Consider the following code:
import React from 'react';
class TestForm extends React.Component {
constructor(props) {
super(props);
}
_submitTest(e) {
e.preventDefault();
this.context.router.transitionTo('/test-next-page', {param_test: 'Test Data'});
}
render() {
return (
<div className="post-content row">
<form className="test-form" method="post" onSubmit={this._submitTest.bind(this)}>
<input type="submit" value="Submit" className="btn btn-primary btn-lg"/>
</form>
</div>
);
}
}
TestForm.contextTypes = {
router: React.PropTypes.object
}
export default TestForm;
the this.context.router.transitionTo() line in the _submitTest() function send me to the test-next-page page/component but i am not seeing the param value in the component!
Am I doing anything wrong in the second parameter of this.context.router.transitionTo()?
After tried different way, I found a solution. I have updated the function this way:
_submitTest(e) {
e.preventDefault();
const my_json_obj = {param_test: 'Test Data'};
this.context.router.transitionTo({
pathname: '/test-next-page',
state: my_json_obj
});
}
Once I moved to the corresponding component of test-next-page path, I found the data in the props. Just like this:
class TestNextPage extends React.Component {
constructor (props) {
super(props);
}
async componentWillMount() {
console.log(this.props); // Here I found the data in state under location object
}
}
Related
I am new in React Js and want to call the parent method from the child method.
There is a class login.jsx when someone clicks on submits button then a method changeUser in FirstPage.jsx should be invoked but when I try the online solution I am getting same error again and again that this.props.changeUser is not a function.
Login.jsx (child class)
import React, { Component } from 'react';
class Login extends Component {
constructor(props){
super(props);
this.state ={
user : null
}
this.onNameChange = this.onNameChange.bind(this);
this.onHandleClick = this.onHandleClick.bind(this);
}
onNameChange = (event)=>{
this.setState({
user:event.target.value
})
}
onHandleClick=(event)=>{
event.preventDefault();
this.props.changeUser("hello");
}
render() {
return (
<form>
<h3>Sign In</h3>
<div>
<label>User Name</label>
<input type="text" name="userId" placeholder="Enter User name" onChange ={this.onNameChange}/>
</div>
<button className="btn btn-primary btn-block" onClick={this.onHandleClick}>Submit</button>
</form>
);
}
}
export default Login;
FirstPage.jsx (parent class)
import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser =(x)=>{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage;import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser =(x)=>{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage;
I am getting an error that TypeError: this.props.changeUser is not a function
Please help me.
try to avoid using a lambda expression within you class component. Just create a simple member function:
import React, { Component } from 'react';
import Login from './Login';
class Firstpage extends Component {
constructor(props){
super(props);
this.state=
{
user:null
}
this.changeUser = this.changeUser.bind(this)
}
changeUser(x) // Try to declare this as member function
{
console.log(x)
}
render() {
return (
<div>
<Login changeUser ={this.changeUser}/>
</div>
);
}
}
export default Firstpage
You are making a mistake here while binding , inside constructor
//WRONG
this.onNameChange = this.onNameChange.bind(this);
this.onHandleClick = this.onHandleClick.bind(this);
//RIGHT
this.onNameChange = onNameChange.bind(this);
this.onHandleClick = onHandleClick.bind(this);
CODE:
constructor(props){
super(props);
this.state ={
user : null
}
this.onNameChange = onNameChange.bind(this);
this.onHandleClick = onHandleClick.bind(this);
}
I want a comment to be posted one after another but not exactly sure how to implement it. Right now, the new comment is replacing the old one. After reading some posts, I think this.props.children could be the answer but stil somewhat confused, so please let me know the best way to implement what I want to. Thanks.
Comment.js:
import React from 'react';
import { Display } from './Display';
export default class Comment extends React.Component {
constructor(props) {
super(props);
this.state = { buttonClicked: false, count: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ buttonClicked: true , count : this.state.count + 1 });
console.log('Button clicked');
}
render() {
const comment_form =(
<div className="posts" >
<input type="text" id="comment-box" name="comment" placeholder="Say something nice." />
<button className="submit-button" type="button" onClick={this.handleClick}>Comment</button>
</div>
);
if (this.state.buttonClicked) {
return (
<div>
{comment_form}
<Display commentNumber={this.state.count} />
</div>
);
} else {
return (<div> {comment_form} </div>);
}
}
}
Display.js:
import React from 'react';
import './App.css';
export class Display extends React.Component {
constructor(props){
super(props);
}
render() {
console.log('display rendered');
const comments = (
<div className="display-comments">
<p>Comment {this.props.commentNumber} :{ document.getElementById('comment-box').value }</p>
</div>
);
return (
<div>
{comments}
</div>
);
}
}
Use the map function to dynamically render the elements.
Link: https://reactjs.org/docs/lists-and-keys.html
The below is App.js file
import React,{Component} from 'react'
//import logo from './logo.svg';
import './App.css'
import InputComponent from "./components/InputComponent";
import ResultComponent from "./components/ResultComponent";
class App extends Component {
render()
{
return (
<div className="App">
<InputComponent />
<ResultComponent/>
</div>
);
}
}
export default App;
The below is InputComponent
import React,{Component} from "react";
import axios from 'axios';
class InputComponent extends Component{
constructor(props) {
super(props)
this.state = {
owner : "",
repo : "",
}
}
//here event.target.value is setting value of target to this owner
ownerName = (event) => {
this.setState({
owner:event.target.value
})
}
//here event.target.value is setting value of target to this repo
repoName = (event) => {
this.setState({
repo:event.target.value
})
}
render(){
//let submit = this.props;
let {items} = this.state;
return(
<div>
<p>The current Owner is {this.state.owner} and the current Repo is {this.state.repo}</p>
<input type='text' onChange={this.ownerName} value={this.state.owner} placeholder='Enter Username' className='inputFields'/>
<br/>
<input type='text' onChange={this.repoName} value={this.state.repo} placeholder='enter Repository' className='inputFields'/>
<br/>
</div>
);
}
}
export default InputComponent;
The below is Result Component
import React,{Component} from "react"
import axios from "axios";
class ResultComponent extends Component{
constructor() {
super()
this.state = {
items: []
}
this.apiFetch=this.apiFetch.bind(this)
}
apiFetch = () => {
axios.get(`https://api.github.com/repos/${this.props.owner}/${this.props.repo}/issues`)
.then(response => {
console.log(response)
this.setState({
items:response.data,
})
})
.catch(error => {
console.log(error)
})
}
render(){
let {items} = this.state;
return(
<div className='submit'>
<button onClick={this.apiFetch}>Fetch Results</button>
<ul>
{items.map(item=>(
<li key={item.id}>
Issue-title: {item.title}
</li>
)
)}
</ul>
</div>
);
}
}
export default ResultComponent
I want to access the value of owner,repo from InputComponent in ResultComponent in my URL part
'''axios.get(https://api.github.com/repos/${this.props.owner}/${this.props.repo}/issues)'''
but not able to do so, can anyone help me what i am doing wrong. I am not able to figure out the issue I am new to React.
In general, there are the options for passing data between react components :
From Parent to Child using Props
From Child to Parent using Callbacks
Between Siblings :
(i) Combine above two methods
(ii) Using Redux
(iii) Using React’s Context API
Use design pattern like HOC or render Props for sharing code between React components (render code abstrait => good practice for reusable)
In your case, it's good pratice with the design pattern render Props. For example, I propose an example of codes :
class InputComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
owner : "",
repo : "",
}
}
//here event.target.value is setting value of target to this owner
ownerName = (event) => {
this.setState({
owner:event.target.value
})
}
//here event.target.value is setting value of target to this repo
repoName = (event) => {
this.setState({
repo:event.target.value
})
}
render() {
return (
<input type='text' onChange={this.ownerName} value={this.state.owner} placeholder='Enter Username' className='inputFields'/>
{/*
use the `render` prop to dynamically determine what to render.
*/}
{this.props.render(this.state)}
</div>
);
}
}
class WithInputComponent extends React.Component {
render() {
return (
<div>
<InputComponent render={dataInput => (
<ResultComponent dataInput={dataInput} />
)}/>
</div>
);
}
}
Here the links in more details :
https://en.reactjs.org/docs/render-props.html
https://towardsdatascience.com/passing-data-between-react-components-parent-children-siblings-a64f89e24ecf
There are three answers to this question:
You should set your state as high on the DOM tree as you can so that
you can pass the values down to siblings. In simple terms, if state
is set by the parent of the two, you can just ask for state from the
parent and you're done.
You can use a state management system like Redux, which effectively
does the same thing behind the scenes.
You can use refs, but you probably shouldn't so ignore that.
If I were you, I would just bring my state up to App.js, modify it from InputComponent, and pass that modified state down to ResultComponent.
class App extends Component {
constructor(props){
super(props)
this.state = {//initial values}
}
changeSomething() {
// function that changes your state's values
}
render()
{
return (
<div className="App">
<InputComponent aFunctionProp={changeSomething} />
<ResultComponent inputVals={this.state}/>
</div>
);
}
}
export default App;
Check this out as well:
https://reactjs.org/tutorial/tutorial.html
Remember that when you pass down props through your component, you refer to them by their prop name, not by the value you pass in. So in InputComponent, you'll be looking for aFunctionProp() rather than changeSomething(). That was pretty confusing to me when I first learned React.
I am trying to pass data from one component to another. but it has no parent child relation and it is independent from each other. I want to do it using flux not redux. Can anyone help me to do this? below are my code.
export class EmpSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
Empnumber: ''
};
}
updateEmpNumber(e) {
this.setState({Empnumber: e.target.value});
}
render() {
return (
<div className="row">
<form>
<div className="form-group">
<label htmlFor="Empnumber">Emp Number</label>
<input type="text" className="form-control" id="Empnumber" placeholder="Emp Number" value={this.state.Empnumber} onChange={this.updateEmpNumber.bind(this)}/>
</div>
</form>
</div>
);
}
}
export default EmpSearch
The other file is where i want to send the EmpNumber is below,
class EmpDetail extends React.Component {
render() {
return (
<div className="container">
<input type="text"/>
</div>
);
}
}
export default EmpDetail;
Assuming you have already implemented the flux architecture in your app.
your 1st component will be like this.
import React from 'react';
import UserAction from '../../Actions/UserActions';
export class EmpSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
Empnumber: ''
};
}
updateEmpNumber(e) {
this.setState({Empnumber: e.target.value});
UserAction.employeeNumb(this.state.Empnumber);
}
render() {
return (
<div className="row">
<form>
<div className="form-group">
<label htmlFor="Empnumber">Emp Number</label>
<input type="text" className="form-control" id="Empnumber" placeholder="Emp Number" value={this.state.Empnumber} onChange={this.updateEmpNumber.bind(this)}/>
</div>
</form>
</div>
);
}
}
export default EmpSearch
The Actions file will look like
import {dispatch,register} from '../Dispatcher/Dispatcher';
export default {
employeeNumb(Data){
dispatch({ actionType:'EMPNO',data:Data});
}
}
The Store will look like
import {dispatch,register} from '../Dispatcher/Dispatcher';
import AppConstants from '../Constants/AppConstants';
import {EventEmitter} from 'events';
const CHANGE_EVENT = 'change';
var a=0;
const UserStore = Object.assign(EventEmitter.prototype,{
emitChange(){
this.emit(CHANGE_EVENT)
},
addChangeListener(callback){
this.on(CHANGE_EVENT,callback);
},
removeChangeListener(callback){
this.removeListener(CHANGE_EVENT,callback)
},
setEmpData(data){
a=data;
},
getEmpData(){
return a;
}
});
dispatcherIndex:register((action)=>{
switch (action.actionType) {
case AppConstants.EMPNO:
UserStore.setEmpData(action.data);
UserStore.emitChange();
break;
}
UserStore.emitChange();
});
export default UserStore;
The dispatcher file
import {Dispatcher} from 'flux';
const flux = new Dispatcher();
export function register(callback){
return flux.register(callback);
}
export function dispatch(actionType,action){
flux.dispatch(actionType,action);
}
and the 2nd Component file looks like
import React from 'react';
import Store from '../../Store/UserStore';
class EmpDetail extends React.Component {
constructor(props){
super(props);
this.state={
empno:''
};
}
componentDidMount(){
Store.addChangeListener(this._onChange);
}
componentWillUnmount = () =>{
Store.removeChangeListener(this._onChange);
}
_onChange = () =>{
this.setState({empno:Store.getEmpData()});
}
render() {
return (
<div className="container">
<input type="text"/>
<input type="button" onClick={()=>{console.log(this.state.empno);}}/>
</div>
);
}
}
export default EmpDetail;
What you have tried might be slightly different but this is the normal flow for what you are looking for.
it is necessary in the method clickSubmitComment(), write logic added to the array of comments text of the textarea, I'm still learning tell me how or share a link.
comment.jsx:
import React from 'react';
export default class Comment extends React.Component {
constructor(props){
super(props);
}
render() {
const comment = this.props.comment.map((commentForm, index) => {
return <CommentForm key={index} {...commentForm}/>
});
return (
<div className="media-body">{comment}<br></br></div>
);
}
}
and, commentForm.jsx:
import React from 'react';
export default class CommentForm extends React.Component {
constructor(props){
super(props);
this.clickSubmitComment = this.clickSubmitComment.bind(this);
this.comments = [];
}
clickSubmitComment() {
textarea -> comments -> send props to comment.jsx and view?
}
render() {
return (
<div><textarea className="form-control" rows="3"></textarea><br></br>
<button type="submit" className="btn btn-primary" onClick={this.clickSubmitComment}>Submit</button></div>
);
}
}
import React from 'react';
export default class Comment extends React.Component {
constructor(props){
super(props);
}
handleCommentChange(text){
// do something with the text
}
render() {
const comment = this.props.comment.map((commentForm, index) => {
return <CommentForm key={index} {...commentForm} handleCommentChange = {this.handleCommentChange.bind(this)}/>
});
return (
<div className="media-body">{comment}<br></br></div>
);
}
}
import React from 'react';
export default class CommentForm extends React.Component {
constructor(props){
super(props);
this.state = {
text: ''
};
this.updateState = this.updateState.bind(this);
}
updateState(e){
this.setState({text: e.target.value});
}
render() {
return (
<div><textarea value={this.state.text} className="form-control" onChange={this.updateState()} rows="3"></textarea><br></br>
<button type="submit" className="btn btn-primary" onClick={this.props.handleCommentChange(this.state.text)}>Submit</button></div>
);
}
}
Add onChange to your textarea and save its value to the state, and then onButton click get the state value. Something like this :
class Test extends React.Component {
constructor(props){
super(props);
this.state = {
comment: ""
}
}
handleComment(e){
this.setState({comment: e.target.value});
}
clickSubmitComment(){
let comment = this.state.comment;
//Do what you will with the comment
}
render(){
return (
<div>
<div><textarea className="form-control" rows="3" onChange={this.handleComment.bind(this)}>{this.state.comment}</textarea><br></br>
<button type="submit" className="btn btn-primary" onClick={this.clickSubmitComment.bind(this)}>Submit</button></div>
</div>
)
}
}
React.render(<Test />, document.getElementById('container'));
Here is a fiddle.