I am very new to react and redux. I have created an application using react/redux. I have implemented routing in the application and also have able to manage the state using redux. Now my problem is After set the state i am only able to get the props in render() not anywhere in the component. below are my code,
export class EmpSearch extends React.Component {
constructor(props) {
super(props);
this.state = {
Empnumber: ''
};
}
EmpSearch = (e) => {
if (e.key === 'Enter') {
browserHistory.push('/Emp/' + e.target.value);
}
}
updateEmpNumber(e) {
this.props.dispatch({
type: 'UPDATE_EMP_NUMBER',
payload: 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.props.Empnumber} onChange={this.updateEmpNumber.bind(this)} onKeyPress={this.EmpSearch}/>
</div>
</form>
</div>
);
}
}
function mapStateToProps(state){
return {
Empnumber: state.Empnumber
}
}
export default connect(mapStateToProps)(EmpSearch);
I want to pass the value to below component but instead of passing and getting value to render i want to create a method and want to pass the props there only.
class EmpDetail extends React.Component {
render() {
const empNumber = this.props.Empnumber;
return (
<div className="container">
Empnumber = {empNumber}
</div>
);
}
}
function mapStateToProps(state){
return {
Empnumber: state.Empnumber
}
}
export default connect(mapStateToProps)(EmpDetail);
I am successfully able to get the props value in render but could not in function.I have tried a lot to to create a method and pass the props to the method and get the props value but could not. Please help me out.
The problem is that you are not binding your function and hence in the function this refers to the context of the function. Also componentDidMount or componentWillMount will be executed only once and hence will contain only the inintial value
Second function
class EmpDetail extends React.Component {
constructor(props) {
super(props);
this.handleProp=this.handleProp.bind(this);
}
componentWillReceiveProps(nextProps) {
this.handleProp(nextProps);
}
handleProp(props) {
console.log('In function' + props.Empnumber);
return props.Empnumber;
}
render() {
const empNumber = this.props.Empnumber;
return (
<div className="container">
Empnumber = {this.props.Empnumber}
</div>
);
}
}
function mapStateToProps(state){
return {
Empnumber: state.Empnumber
}
}
export default connect(mapStateToProps)(EmpDetail);
Related
I have a React component render method defined as below, which includes passing a prop called onExchangeSelect into the ExchangeList component.
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => this.setState({selectedExchange})}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
Then, in the ExchangeList constructor, when I console.log this.props, there is not a prop called onExchangeSelect which I can call and th.
The intent is to pass a callback function from the top level component to a child component, to be called by the child so as to affect the state of the parent component. The entire top-level class is below:
class ExchangeContainer extends Component {
constructor(props) {
super(props);
this.state = {
exchanges:[
{
name:"binance",
url:"https://bittrex.com"
},
{
name:"bittrex",
url:"https://bittrex.com"
}
],
selectedExchange:"binance"
};
}
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => this.setState({selectedExchange})}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
}
Why is the function not available as a prop in the child component? (below):
class ExchangeList extends Component {
constructor(props) {
super(props);
this.state = {
};
console.log('This props ' + JSON.stringify(this.props))
}
render() {
console.log("EL: " + JSON.stringify(this.props))
const ExItemList = this.props.exchanges.map((exchange) => {
return <ExchangeListItem key={exchange.name} exchange={exchange}
onExchangeSelect={this.props.onExchangeSelect}/>
});
return (
<ul className="col-md-4 list-group bg-light" >
{ExItemList}
</ul>
);
}
}
i would inspect them in dev tools instead of console.log..place break point and check in chrome dev tool.. onExchangeSelect should be available as part of props in child component..
the offical docs says you should bind the method to a property inside the constructor function. you can play around on my codesandbox for the code below
constructor(props) {
super(props);
this.state = {
exchanges: [
{
name: "binance",
url: "https://bittrex.com"
},
{
name: "bittrex",
url: "https://bittrex.com"
}
],
selectedExchange: "binance"
};
// bind "this" to handleOnExchange method
this.handleOnExchange = this.handleOnExchange.bind(this);
}
// method to be bound
handleOnExchange (data) {
this.setState({selectedExchange: data})
}
render() {
const ExchangeList = props => <div />;
const ExchangeDetail = props => <div />;
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges}
selected={this.state.selectedExchange}
// pass the method to a child property (onExchangeSelect)
onExchangeSelect={this.handleOnExchange}
/>
<ExchangeDetail selectedExchange={this.state.selectedExchange} />
</div>
);
}
to use it inside a (class-based) child component, call the method with an arg like this:
this.props.onExchangeSelect(arg)
The reason it can't see it is because you are looking for it in the wrong place. You are looping through the "exchange" props to create a new component so when you reference "this.props.onExchangeSelect", you are not referring the the props passed to the class as you expected but to the exchange object through which you are looping.
To remedy this, consider rewriting the ExchangeContainer component like so:
class ExchangeContainer extends Component {
constructor(props) {
super(props);
this.state = {
exchanges:[
{
name:"binance",
url:"https://bittrex.com"
},
{
name:"bittrex",
url:"https://bittrex.com"
}
],
selectedExchange:"binance"
};
}
setSelectedExchange = (selectedExchange) =>{
this.setState({selectedExchange})
};
render() {
return (
<div className="ExchangeContainer list-group">
<ExchangeList
exchanges={this.state.exchanges} selected={this.state.selectedExchange}
onExchangeSelect={selectedExchange => setSelectedExchange(selectedExchange)}
/>
<ExchangeDetail exchange={this.state.selectedExchange} />
</div>
);
}
}
And the ExchangeList component like so:
class ExchangeList extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
console.log("EL: " + JSON.stringify(this.props));
const {exchanges, selected, onExchangeSelect} = this.props;
const ExItemList = exchanges.map((exchange) => {
return <ExchangeListItem key={exchange.name} exchange={exchange}
onExchangeSelect={onExchangeSelect}/>
});
return (
<ul className="col-md-4 list-group bg-light" >
{ExItemList}
</ul>
);
}
}
I have 2 Components one called NodeWidget and another called PopupWidget. In the NodeWidget it has a Model assigned to it which looks like the following:
PopupModel
export class PopupModel {
question: string;
model: string;
constructor(question: string, model: string) {
this.question = question;
this.model = model;
}
}
The parent Component is NodeWidget which passes in the Model to the PopupWidget with data in.
NodeWidget
{ this.state.showComponent ?
<PopupWidget model={this.props.popupModel} /> :
null
}
Then finally in the child Component we have this code:
export interface PopupWidgetProps {
model: PopupModel;
}
export interface PopupWidgetState { }
export class PopupWidget extends React.Component<PopupWidgetProps, PopupWidgetState> {
constructor(props: PopupWidgetProps) {
super(props);
this.state = { };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this.props);
}
render() {
return (
<div className="popup">
<div className="popup_inner">
<h1>TEST</h1>
<input type="text" value={this.props.model.question} placeholder="Write a question..." />
<button onClick={this.handleClick}>close me</button>
</div>
</div>
);
}
}
I want to be able to bind the value of the input to the model and then for it to update the original model in the Parent Component, am i doing this correctly as it does not seem to work.
You can do this to pass the input result to parent component on the button click:
PopupWidget :
export class PopupWidget extends React.Component<PopupWidgetProps, PopupWidgetState> {
constructor(props: PopupWidgetProps) {
super(props);
this.state = { question: '' };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.inputResult(this.state.question)
}
render() {
return (
<div className="popup">
<div className="popup_inner">
<h1>TEST</h1>
<input type="text" value={this.state.question} onChange={(question) => { this.setState({ question })}} placeholder="Write a question..." />
<button onClick={this.handleClick}>close me</button>
</div>
</div>
);
}
}
NodeWidget :
constructor(props) {
super(props);
this.getInputResult = this.getInputResult.bind(this);
}
getInputResult(question) {
this.props.inputResult(question);
this.setState({ showComponent: false });
}
...
{ this.state.showComponent ?
<PopupWidget inputResult={this.getInputResult} /> :
null
}
Finally in PopupModel (i assume this is a react component, i don't know if you can work with simple es6 class in react):
export class PopupModel extends React.Component {
constructor(props) {
this.state = { question: '', model: '' }; // set your initial state
this.getInputResult = this.getInputResult.bind(this);
}
getInputResult(question) {
this.setState({ question }); // here's our result from the input
}
render(){
return(<NodeWidget inputResult={this.getInputResult} />);
}
}
This can be pretty boring to handle if you have multiple components between the two which have to communicate.
You can use a HOC like Redux or MobX to handle an app state that can be passed in any component, and any component can dispatch actions to update the app state, you should go for it if you have multiple cases like this.
I have a class of this form:
export default class FixedMem {
constructor(totalMem){
this._totalMem = totalMem
}
get totalMem(){
return this._totalMem
}
addMem(mem){
this._totalMem += mem
}
}
I import it into my react component like this :
import Fixed from '../somewhere'
If i want to create a new classes with varying parameters based on input from a textbox and display its values. How do i call its methods from inside the render method ?. This somewhat illustrates my problem
class fixedBlock extends Component {
constructor(){
super()
this.state = {
"textInput":"",
"totalMem":0,
"fixed":null
}
}
handleInputChanged(e){
this.setState({
"textInput":e.target.value
})
}
handleButtonPressed(){
this.setState({"fixed":new Fixed(parseInt(this.state.textInput))})
}
incrementButtonPressed(){
this.state.fixed.addMem(2)
}
render(){
return(
<div>
<input type="button" onClick={this.handleInputChanged} value=
{this.state.textInput}>
<button onClick={this.handleButtonPressed}>create</button>
<button onClick={this.incrementButtonPressed}> increment </button>
<p>{this.state.fixed.totalMem}</p>
</div>
)
}
}
this doesn't work, another approach i had to solve this problem was using closures, so inside my react component :
class fixedBlock extends Component{
constructor(){//stuff here}
FixedMem () {
var FixedObj = null
return {
initFixed: function (totalMem) {
FixedObj = new Fixed(totalMem, divisions)
},
totalMem: function () {
return FixedObj.totalMem
},
increment: function(){
FixedObj.addMem(2)
}
render(){//stuff here}
}
How do i even use this in the render method ?
There are several issues with your code example. Missing closing tags and rebinding of methods missing.
Here's an example of dynamically usage of a class instance in a React component. However I can not recommend to use this approach. This is mainly as proof of concept.
class MyValue {
constructor(val) {
this._val = parseInt(val, 10) || 0;
}
get total() {
return this._val;
}
set total(val) {
this.val = val;
}
add(val) {
this._val += val;
}
subtract(val) {
this._val -= val;
}
}
Here's the React component
class Block extends React.Component {
constructor() {
super();
this.state = {
textInput: "",
myValue: new MyValue()
};
}
handleInputChanged(e) {
this.setState({
textInput: e.target.value
});
}
handleButtonPressed() {
this.setState({ myValue: new MyValue(this.state.textInput) });
}
incrementButtonPressed() {
this.state.myValue.add(2);
this.forceUpdate(); /* React does not know the state has updated, force update */
}
render() {
return (
<div>
<input type="number" step="1" onChange={this.handleInputChanged.bind(this)} />
<button onClick={this.handleButtonPressed.bind(this)}>create</button>
<button onClick={this.incrementButtonPressed.bind(this)}>increment</button>
<p>{this.state.myValue.total}</p>
</div>
);
}
}
As an alternative approach. You could use a pattern where you separate logic from presentation. Here's an example using function as child. The Calculator handles the calculation and Presentation uses the calculator and present the GUI.
class Calculator extends React.Component {
constructor() {
super();
this.state = {value: 0};
}
add(value){
this.setState(prevState => ({value: prevState.value + value}));
}
subtract(value){
this.setState(prevState => ({value: prevState.value - value}));
}
set(){
this.setState(prevState => ({value: parseInt(prevState.input, 10) || 0}));
}
input(value){
this.setState({input: value});
}
render() {
return this.props.children(
{
value: this.state.value,
add: this.add.bind(this),
subtract: this.subtract.bind(this),
set: this.set.bind(this),
input: this.input.bind(this),
});
}
}
const Presentation = props => (
<Calculator>
{ ({value,add,subtract,set,input}) => (
<div>
<button onClick={() => add(2)}>add 2</button>
<button onClick={() => subtract(3)}>subtract 3</button>
<input type="number" step="1" onChange={e => input(e.target.value)} />
<button onClick={set}>set</button>
<p>{value}</p>
</div>)
}
</Calculator>);
The problem with the first attempt is that you are mutating a Component's state without letting React know about it. You need to use setState() or forceUpdate(). One way to still have FixedMem manage your state while letting React know could be:
class FixedBlock extends Component {
constructor(props) {
super(props);
this.state = {
textInput: '',
totalMem: 0
};
this.fixedMem = new FixedMem(0);
this.sync = this.sync.bind(this);
}
sync() {
const totalMem = this.fixedMem.totalMem;
this.setState({ totalMem });
}
handleInputChanged(evt) {
this.setState({ textInput: evt.target.value });
}
handleButtonPressed() {
this.fixedMem = new FixedMem(parseInt(this.state.textInput));
this.sync();
}
incrementButtonPressed() {
this.fixedMem.addMem(2);
this.sync();
}
render() {
return (
<div>
<input type="text" onChange={this.handleInputChanged.bind(this)} />
<button onClick={this.handleButtonPressed.bind(this)}>create</button>
<button onClick={this.incrementButtonPressed.bind(this)}>increment</button>
<p>{this.state.totalMem}</p>
</div>
);
}
}
I'm trying to execute a very simple example with ReduxForm and I have two functions before the render, but one of the functions call another as a component props, but then it is undefined. I tried to bind the this but it still dont recognise it.
Here is my code:
import React, { Component } from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
class Page4 extends Component {
constructor(props) {
super(props)
this.simpleField.bind(this)
}
simpleField(field) {
const { meta } = field
return (
<div className='form-group'>
<label>{field.label}</label>
<input
className='form-control'
{...field.input}
/>
</div>
)
}
// This function cannot reach the simpleField component
myFields(field) {
let optiosArray = [
{'label':'Option 1', 'value':'1'},
{'label':'Option 2', 'value':'2'}
]
return(
optionsArray.map((option, key) => {
<Field
label= {option.label}
value= {option.value}
name={option.value}
component={this.simpleField}
/>
})
)
}
render() {
return (
<div>
<FieldArray
name='test'
label='label'
component={this.myFields}
/>
</div>
)
}
}
const validate = (value) => {
const errors = ''
return errors
}
export default reduxForm({
validate,
form: 'Page4'
})(Page4)
To access this.simpleFields, binding the this.myFields in the constructor is good enough.
constructor(props) {
super(props)
this.myFields = this.myFields.bind(this)
}
this.myFields = this.myFields.bind(this)
I think you are using the FieldArray incorrectly. I've modified the code so that it will give you an idea on how FieldArray should be used. Working jsFiddle here - https://jsfiddle.net/sherin81/4u3hk7kg/
class Page4 extends Component {
constructor(props) {
super(props)
this.myFields = this.myFields.bind(this)
}
simpleField = (field) => {
const { input: { value } } = field
return (
<div className='form-group'>
<input type="text" name={field.input.name} onChange={field.input.onChange} value={value} />
</div>
)
}
myFields({ fields }) {
return (<div>{fields.map((option, key) => {
return (<div key={key}>
<Field
name={option}
component={this.simpleField}
/>
</div>)
})}</div>)
}
render() {
return (
<div>
<FieldArray
name='listOfTextFields'
component={this.myFields}
/>
</div>
)
}
}
const validate = (value) => {
const errors = ''
return errors
}
const MyTextFields = reduxForm({
validate,
form: 'Page4'
})(Page4)
And when calling the component, you should do the following.
<MyTextFields initialValues={{ listOfTextFields: [ 'Text 1','Text 2' ] }}/>
You did bind the wrong function. You are trying to access this in your myFields() function. Therefore you have to bind this one and not simpleField().
You have to bind your methods ether in the constructor:
class Page4 extends Component {
constructor(props) {
super(props);
this.myFields.bind(this);
}
myFields(...) {
....
}
}
or if you use babel and ES6, you can use an arrow function. This way it will be automatically bound:
class Page4 extends Component {
myFields = (field) => {
....
};
}
Do not bind functions in the render cycle because that means you would create a new callback on every render.
I am facing an issue with react and I am totally stuck. I have 3 components: channel as a parent and header and story as a children:
class Channel extends React.Component {
constructor(props) {
super();
}
componentDidMount() {
this.props.getChannels();
}
render() {
return (
<div>
<div className="col-xs-12 col-md-8 col-lg-8>
<div className="row">
<Header activeChannelList={this.props.channels.channelsArr}/>
</div>
<div className="row">
{
this.props.channels.channelsArr.map((item, i) => <StoryBoard
newsChanel={item}
key={"storyBoard" + i}
></StoryBoard>)
}
</div>
</div>
<div className="col-xs-12 col-md-2 col-lg-2 color2">.col-sm-4</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
channels: state.channelReducer
};
};
const mapDispatchToProps = (dispatch) => {
return {
getChannels: () => {
dispatch(getChannels());
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Channel);
As you can see I have a ajax call with this.props.getChannels(); and I put it in componentDidMount to make sure that it is called before rendering then after I pass the channels to the Header ans story which are children components.
Now my problem is when I try to access it in Header via console.log(this.props.activeChannelList); I get 0 thought I should have 5 channels. More intrestingly when I try to access the props I send in Stroryboard I can easily access them without any problem. The following is my code for Header:
export class Header extends React.Component {
constructor(props) {
super();
}
componentDidMount() {
console.log("dddddddddddddddddddddddddddddddddddddddddd");
console.log(this.props.activeChannelList);// I get 0 though I should get 5
}
render() {
return (
<div className="col-xs-12 header tjHeaderDummy">
<div className="col-xs-1"></div>
</div>
);
}
}
And my storyboard is :
class StoryBoard extends React.Component {
constructor(props) {
super();
}
componentDidMount() {
if(this.props.isFreshLoad ){
do sth
}
}
render() {
return (
<div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
stories: state.storyBoardReducer
};
};
const mapDispatchToProps = (dispatch) => {
return {
//some funcs
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(StoryBoard);
Can anyone help?
U r printing the value in componentDidMount method in Header component, this lifecycle method get called only once, if ur api response come after the rendering of Header, it will never print 5, put the console in render method, so that at any time when u get the response it will populate the value.
From Docs:
componentDidMount: is invoked immediately after a component is mounted
first time. This is where AJAX requests and DOM or state updates
should occur.
Try this Header Comp, it will print the proper value:
export class Header extends React.Component {
constructor(props) {
super();
}
componentDidMount() {
}
render() {
return (
<div className="col-xs-12">
{this.props.activeChannelList}
</div>
);
}
}