I would like to create a state object that combines both the state value itself and the ability to call setState whenever its value is changed. This way, e.g. on the interface between the container and the dumb component I won't have to pass a separate setter for each state property.
E.g. typically what gets done in the 'smart and dumb' pattern is the following:
let TextValueContainer = React.createClass({
getInitialState: function () {
return {value: ''};
},
setValue(v) {
this.setState({value: v});
},
render: function() {
return (
<TextValue
value={this.state.value}
setValue={this.setValue}
/>
);
}
});
let TextValue = React.createClass({
propTypes: {
value: React.PropTypes.string.isRequired,
setValue: React.PropTypes.func.isRequired
},
render: function() {
return (
<input type={'text'}
onChange={function (ev) {
this.props.setValue(ev.target.value);
}.bind(this)}
value={this.props.value}
>
</input>
);
}
});
ReactDOM.render(<TextValueContainer/>, $('#app')[0]);
Observe how at the interface between the container and the dumb component two properties are passed: the state value itself (value) and a method to change it (setValue). For N separate state attributes I would need 2*N props to be passed at the interface. Plus, there is no hard way looking at the code of the dumb component to figure out which setter is for which value.
I experimented a bit and come up with the following:
class StateHolder {
constructor(v, that) {
this.v = v;
this.setState = function(v2) {
this.setState(Object.assign({}
,this.state
,{valueHolder: new StateHolder(v2, that)}));
}.bind(that);
}
}
let TextValueContainer = React.createClass({
getInitialState: function () {
return {valueHolder: new StateHolder('', this)};
},
render: function() {
return (
<TextValue
valueHolder={this.state.valueHolder}
/>
);
}
});
let TextValue = React.createClass({
propTypes: {
valueHolder: React.PropTypes.instanceOf(StateHolder).isRequired
},
render: function() {
return (
<input type={'text'}
onChange={function (ev) {
this.props.valueHolder.setState(ev.target.value);
}.bind(this)}
value={this.props.valueHolder.v}
>
</input>
);
}
});
ReactDOM.render(<TextValueContainer/>, $('#app')[0]);
In the above implementation for each attribute, only a single props needs to be passed between the 'smart' and the 'dumb' component (in the example above valueHolder).
My questions are:
is there a simpler way to accomplish what I am trying to do? (i.e. simplify the interface between the 'smart' and the 'dumb' component and make explicit the association between the values passed down and their setter functions)
do you see any anti-patterns or code smells in the "solution" given above?
Looks like you'd want to take a look at some framework to manage your flow of data and the corresponding changes in the app state. I've been working with Redux a lot recently and I would recommend it. It's a very smart implementation of the Flux architecture. Your "stateHolder" concept is resolved in the Redux store.
From the Redux motivation page
Following in the steps of Flux, CQRS, and Event Sourcing, Redux
attempts to make state mutations predictable by imposing certain
restrictions on how and when updates can happen. These restrictions
are reflected in the three principles of Redux.
Of course, there are alternatives to Redux; the point is that what you're trying to do would become really hard to maintain and understand and that you should look at a generalised way to manage your state.
Tell me what do you think about this JSBin: http://jsbin.com/tofepoliha/edit?js,output
First, when declaring the TextValue element, instead of using value={this.state.value} value2={this.state.value2}, we pass the whole state in one action using the spread (...) operator.
<TextValue {...this.state} setValue={this.setValue} />
This way we don't need to repeat ourselves for each and every property. Now, for the setValue function - instead of having a special function for every property, we can simply declare one generic function, that gets the key and the value and sets it to the parent component's state:
setValue(value, v) {
this.setState({[value]: v});
}
Then, we can have as many inputs (or every other element for this matter) like so:
<input type="text" onChange={function (ev) {
this.props.setValue('value', ev.target.value);
}.bind(this)} value={this.props.value} />
<input type="text" onChange={function (ev) {
this.props.setValue('value2', ev.target.value);
}.bind(this)} value={this.props.value2} />
Related
If I create a component like this:
const MyInput = ({username})=>{
return (
<div>
<input type="text" value={username}/>
</div>
);
};
nothing will happen when I type in the input, because react needs to call setState() to update it.
so what I do is add a onChange method to handle it:
handleOnchange(e){
e.preventDefault();
let name=e.target.value;
this.setState({username:name});
}
But I think having to handle every onChange manually is too much boilerplate, Is this a better way to save the value? can it be done using ref?
Fiddle Link
Yes, you need to call setState in order for the value to update on the input.
See here for a good example: https://facebook.github.io/react/docs/forms.html
Copied here:
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
return (
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
);
}
There is a solution to this issue that is common in javascript and implemented by lodash. Take a look at using debouncing to wait for the user to stop entering text before trying to update. Here is an analogy of how it works from someone more eloquent than me:
Think of it as "grouping multiple events in one". Imagine that you go
home, enter in the elevator, doors are closing... and suddenly your
neighbor appears in the hall and tries to jump on the elevator. Be
polite! and open the doors for him: you are debouncing the elevator
departure. Consider that the same situation can happen again with a
third person, and so on... probably delaying the departure several
minutes.
To do this in react you would import lodash and set onChange to be _.debounce(function(), delay) where function() would setState after the given delay.
This demo does a great job demoing how debounce works in react (just open the console and watch it as you type).
If you want to learn about best practices with debounced functions read the answers in this SO post.
Ps: you can also try throttling, though I think debouncing will be more desirable for your specific use case. The post with the analogy on debouncing also has one on throttling. To use it you would replace _.debounce(function, int) with _.throttle(function, int) in the examples
You can value link in react to implement 2 way data binding
class Something extends React.Component {
state = {
email: ''
}
emailValueLink = (value) => {
return {
value: this.state.email,
requestChange: this.handleEmailChange
};
}
handleEmailChange(newEmail) {
this.setState({email: newEmail});
}
render() {
<input type="email" valueLink={this.emailValueLink()} />
}
}
You can generalise emailValuelink by passing it in the key of the state to bind
React is all about splitting your code into components. So to prevent retyping this boilerplate code, you can create a component and reuse it for all form elements.
Or, like others have said, you can take somebody else's form or databinding components and reuse those.
This is not a question as much "how to make this work" as much as it is a "was this the best way." Here's my code:
/**
* React Static Boilerplate
* https://github.com/koistya/react-static-boilerplate
* Copyright (c) Konstantin Tarkus (#koistya) | MIT license
*/
import React, { Component } from 'react';
// import './InputWidgetText.scss';
import ContentBlock from '../ContentBlock';
var i = 0;
var contentBlocks = [];
var ContentContainer = React.createClass({
addNewBlock: function(){
i++;
contentBlocks.push(<ContentBlock key={i} index={i}/>)
this.forceUpdate();
},
render: function(){
if (this.props.inputs) {
contentBlocks = this.props.inputs.map(function(item, index){
i++;
return(<ContentBlock key={index} index={index} content={item} />)
});
}
return (
<div>
{contentBlocks}
<button onClick={this.addNewBlock}>+</button>
</div>
)
}
});
export {ContentContainer as default};
The problem is that every so often on a refresh the props.inputs are not getting passed down to this component and throwing an error when I try to map undefined. So the simple solution is to put the map process in an if check for whether or not the props are there yet - is that actually the right way to handle this? My data is passed in via a reflux mixin on the parent. I just feel like there might be a more proper way to handle this. Thanks for the feedback!
May I strongly suggest you refactor your code to do away with the file variables i and contentBlocks.
The contentBlocks variable seems completely unnecessary, whilst your i variable should be part of the state. Whilst you're at it, give i a more meaningful name, e.g. blockCount.
getInitialState: function () {
return {
blockCount: 0
};
},
Then define your click event handler to modify the state:
addNewBlock: function () {
this.setState({
blockCount: this.state.blockCount + 1
});
},
Every time you call setState(), React will trigger a re-render. You should never need to call forceUpdate().
Finally, your render() function should return its content based SOLELY on this.props and this.state. That is, for any given props and state, the output will be predictable. Think of this.props and this.state as input parameters to the render() function. That is all render() can, or needs to, know about.
I won't try to write the render() function as I'm not sure exactly what you're trying to achieve with this component. But for a given this.props.input and this.state.blockCount (or whatever you choose to use as props and state) you should know exactly what you're outputting.
I know I haven't directly answered the question you put, but I hope this clarifies some React concepts.
If I'm, using complex object Structure in React render, how can I avoid redefining that structure in getInitialState method
var UserGist = React.createClass({
getInitialState: function() {
return {
user:{
section: {
country: 'Iran'
}
},
lastGistUrl: ''
};
},
....
....
render: function() {
return (
<div>
{this.state.user.section.country}'s Amex Initial
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
Now the problem is the actual structure of the object used is pretty huge
user:{
section: {
.....
25 levels of nesting
.....{
country: 'Iran'
}
}
}
and that object is coming from backend , so how can I avoid defining the entire object structure in getInitialState()
First of all, state should be shallow. You shouldn't have deep objects as props or state.
Next, why do you even want to do this? Is it so that you don't get a bunch of "xx is not defined" errors on the initial render? If so, why don't you just declare user: {} in getInitialState, and wrap an if (!_.isEmpty(this.state.user)) condition around your render code?
Or, since the data is coming from the server, maybe it's a good thing to re-declare this structure. You can use getInitialState to create placeholder data until the real object shows up.
Also, be aware that setState only does a shallow replacement. If you change any property or sub-property of the user object, you'll need to clone it, change the property, and then call setState({user: clonedAndUpdatedUser}). Or, just call forceUpdate.
You should really just try to get your props and state to be shallow.
Good luck!
I have just started to study ReactJS and have some questions. I was reading documentation here, but I can't find the answer I am looking for. Here is an example:
var Awesome = React.createClass({
getInitialState:function() {
return {
txt : ["1","2","3","4","5"],
isTrue : true
}
},
handleClick:function() {
this.setState({
isTrue : !this.state.isTrue
})
},
render:function() {
var changeStyle = {
display: this.state.isTrue ? "block" : "none"
};
var message = this.state.txt.map(function(oneMessage) {
return <SubChild change={changeStyle} txt={oneMessage}/>
});
return (
<div>
<button onClick={this.handleClick} >Click Me</button>
{message}
</div>
)
}
})
var SubChild = React.createClass({
render:function() {
return (
<div style={this.props.change}>
<h3>{this.props.txt}</h3>
</div>
)
}
})
React.render(<Awesome />, document.body)
Everything works fine, but I have some questions. As you can see I store my state inside a variable. Is this the best practice? How can I achieve the same result without variables inside render function or actually without states (I am trying to avoid state). Is this possible?
Here is my Fiddle
Why State Variables?
The idea of using state variables is to have changing / dynamic data, ie if anything about the component is changing, it should be defined as a state variable in the component so user interaction can result in change of this variable and a change in this variable causes the effected component to re-render.
Use of Properties
If some value is changed for each instance of the component and is uneffected by user interaction or component state change, it should be defined as a property so it can be assigned only once at instantiation.
In all cases, we cannot really avoid the use of variables inside the render
I have come across a problem about states based on properties.
The scenario
I have a Component parent which creates passes a property to a child component.
The Child component reacts according to the property received.
In React the "only" proper way to change the state of a component is using the functions componentWillMount or componentDidMount and componentWillReceiveProps as far as I've seen (among others, but let's focus on these ones, because getInitialState is just executed once).
My problem/Question
If I receive a new property from the parent and I want to change the state, only the function componentWillReceiveProps will be executed and will allowed me to execute setState. Render does not allow to setStatus.
What if I want to set the state on the beginning and the time it receives a new property?
So I have to set it on getInitialState or componentWillMount/componentDidMount. Then you have to change the state depending on the properties using componentWillReceiveProps.
This is a problem when your state highly depends from your properties, which is almost always. Which can become silly because you have to repeat the states you want to update according to the new property.
My solution
I have created a new method that it's called on componentWillMount and on componentWillReceiveProps. I have not found any method been called after a property has been updated before render and also the first time the Component is mounted. Then there would not be a need to do this silly workaround.
Anyway, here the question: is not there any better option to update the state when a new property is received or changed?
/*...*/
/**
* To be called before mounted and before updating props
* #param props
*/
prepareComponentState: function (props) {
var usedProps = props || this.props;
//set data on state/template
var currentResponses = this.state.candidatesResponses.filter(function (elem) {
return elem.questionId === usedProps.currentQuestion.id;
});
this.setState({
currentResponses: currentResponses,
activeAnswer: null
});
},
componentWillMount: function () {
this.prepareComponentState();
},
componentWillReceiveProps: function (nextProps) {
this.prepareComponentState(nextProps);
},
/*...*/
I feel a bit stupid, I guess I'm loosing something...
I guess there is another solution to solve this.
And yeah, I already know about this:
https://facebook.github.io/react/tips/props-in-getInitialState-as-anti-pattern.html
I've found that this pattern is usually not very necessary. In the general case (not always), I've found that setting state based on changed properties is a bit of an anti-pattern; instead, simply derive the necessary local state at render time.
render: function() {
var currentResponses = this.state.candidatesResponses.filter(function (elem) {
return elem.questionId === this.props.currentQuestion.id;
});
return ...; // use currentResponses instead of this.state.currentResponses
}
However, in some cases, it can make sense to cache this data (e.g. maybe calculating it is prohibitively expensive), or you just need to know when the props are set/changed for some other reason. In that case, I would use basically the pattern you've written in your question.
If you really don't like typing it out, you could formalize this new method as a mixin. For example:
var PropsSetOrChangeMixin = {
componentWillMount: function() {
this.onPropsSetOrChange(this.props);
},
componentWillReceiveProps: function(nextProps) {
this.onPropsSetOrChange(nextProps);
}
};
React.createClass({
mixins: [PropsSetOrChangeMixin],
onPropsSetOrChange: function(props) {
var currentResponses = this.state.candidatesResponses.filter(function (elem) {
return elem.questionId === props.currentQuestion.id;
});
this.setState({
currentResponses: currentResponses,
activeAnswer: null
});
},
// ...
});
Of course, if you're using class-based React components, you'd need to find some alternative solution (e.g. inheritance, or custom JS mixins) since they don't get React-style mixins right now.
(For what it's worth, I think the code is much clearer using the explicit methods; I'd probably write it like this:)
componentWillMount: function () {
this.prepareComponentState(this.props);
},
componentWillReceiveProps: function (nextProps) {
this.prepareComponentState(nextProps);
},
prepareComponentState: function (props) {
//set data on state/template
var currentResponses = this.state.candidatesResponses.filter(function (elem) {
return elem.questionId === props.currentQuestion.id;
});
this.setState({
currentResponses: currentResponses,
activeAnswer: null
});
},