relative time in redux reactjs - reactjs

I have some data with datetime fields , i want to show the relative date time using momentJS fromNow(). However after the initial load it shows timestamp as a few seconds ago. But this will not be updated until a next state change triggered. Is it a good practice to keep another state in the state-tree & control via a timer function setInterval in componentDidUpdate?
render()
{
// get the new prop value here which triggered from a setInterval -> action -> reducer -> state change -> propagate to connected components
const text = comment.get('text');
const dateTime = moment(comment.get('dateTime')).fromNow();
return (
// add the new prop into the component
<div key={id}>
<Comment
text = {text}
dateTime = {dateTime}
</div>
}

I scribbled down a component that takes an epoch time timestamp and display a momentjs text for it.
The text is updates via inner component state every 300ms which you can change however you'd like.
You can notice on this fiddle, every new text is logged in the console. After 45 seconds you should see the text change from "a few seconds ago" to "a minute ago".
Fiddle here, this is the code:
var MomentTime = React.createClass({
getInitialState: function() {
return {text: ""};
},
componentWillMount: function() {
this._updateMomentText();
this.interval = setInterval(this._updateMomentText, 300);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
_updateMomentText: function() {
var text = moment(this.props.timestamp).fromNow()
console.log(text)
if(text !== this.state.text) {
this.setState({text: text});
}
},
render: function() {
return <div>{this.state.text}</div>;
}
});
ReactDOM.render(
<MomentTime timestamp={new Date().getTime()} />,
document.getElementById('container')
);

Related

accessing state data in componentDidMount

Why is it not possible to access this.state.board within componentDidMount? As I understand it, once the component has been rendered, componentDidMount is fired immediately after, and only once.
I am trying to set up a Google Analytics ecommerce tracker, and so I thought the best place to set that up would be within the componentDidMount because it ensures that the GA tracker is called only once. However, I am not able to access any of the state data to send back to GA. Any ideas?
//function which establishes state
function getEditorState() {
var board = Editor.getCsb();
var similarBoard = Editor.getSimilarLsbs();
return {
board: board,
similarBoard: similarBoard,
editing: Editor.isEditing(),
hoverColor: Editor.getHoverColor(),
variant: Editor.variant(),
lidAndLsb: Editor.getLidAndLsb()
};
}
//component
var CsbEditorApp = React.createClass({
getInitialState: function () {
return getEditorState();
},
componentDidMount: function () {
console.log(this.state.board); // <---- this returns an empty object.
Editor.addChangeListener(this._onChange);
SbAction.loadCsb(this.props.params.cid);
},
render: function() {
console.log(this.state.board); // <---- this returns the the board object with data.
return (
<div className={cm('lightbox sb-bg overlay-border')} ref="app">
<Header board={this.state.board} label={this.state.label} socialLinkStatus={this.state.socialLinkStatus} buyingAll={this.state.buyingAll} />
<div className="viewer-content">
<div id="csb-content">
<MetaText className="meta-author" metaKey="author" board={this.state.board} />
<BoardMeta board={this.state.board}/>
<CsbPanel board={this.state.board hoverColor={this.state.hoverColor} showPanel={showPanel} />
<RouteHandler/>
</div>
</div>
</div>
);
},
_onChange: function () {
this.setState(getEditorState());
$("#cc_hover").hide();
}
});
console.log is not a reliable method of debugging - the method is async and actually can get called after you've set up your listener or even after the callback it registers (which affects the state) has been triggered, so use the debugger. Also, try commenting out the Editor.addChangeListener(this._onChange); line and see if it causes the problem.

How to change state of a non-related component from a timer component in React

I have a Timer component that is started with a click of a button:
handleClick: function() {
if (this.state.running == 0) {
this.setState({running: 1});
ReactDOM.render(<Timer start={Date.now()} round={0} />,document.getElementById('timer'));
}
},
render: function() {
return (
<button onClick={this.handleClick}>Začni simulacijo</button>
);
}
this sets off the Timer which has a tick function that checks if it needs to update a table of values (also a React component)...this happens here:
tick: function(){
round = Math.floor(this.state.elapsed / seasonParams.gameDayTime);
if (round > this.state.round) {
var result = config.pairs.filter(function( obj ) {
return obj.round == round;
});
this.setState({elapsed: new Date() this.props.start,"round":round }); //this sets state of timer component
//HERE I WOULD NEED TO ADD SET STATE OF THE TABLE COMPONENT
}
console.log("elapsed: "+this.state.elapsed+", round: "+round);
},
The Table component accepts an array of object to render the table...but is not related to the Timer or Button component. How do I pass the newly found data to it in the Timer?
Thank you...

Safe to set on this.state just to keep track?

I was wondering if it is safe to set .state when I need to keep track.
My component, allows user to click it, every time they do it increments tieId. On mouse exit of the component, if the tieId is different from when they mouse enetered the component, I want to do a save.
I had to keep track on this.state
Is this code approptiate or will it break the React diff checking as I didn't use this.setState{tieId: ...}?
var HelloMessage = React.createClass({
getInitialState: function() {
return {tieId: -1, onEnt: -1};
},
click: function(e) {
this.state.tieId++;
if (this.state.tieId > 2) {
this.state.tieId= -1;
}
},
mouseEnter: function(e) {
this.state.onEnt = this.state.tieId
},
mouseLeave: function(e) {
if (this.state.tieId != this.state.onEnt) {
alert('ok saving');
} else {
alert('will not save because tie id is same as when entered \n tieId: ' + this.state.tieId + ' \n onEnt: ' + this.state.onEnt);
}
},
render: function() {
return <div onClick={this.click} onMouseLeave={this.mouseLeave} onMouseEnter={this.mouseEnter} >Hello </div>;
}
});
ReactDOM.render(<HelloMessage />, mountNode);
Can copy paste this code at the React site Live JSX editor - http://facebook.github.io/react/
You should always use setState() to make changes to your component state in React.
In case you don't believe me, here's Dan Abramov saying the same thing :)
(There's an exception if you're using ES6 classes: your constructor should set state directly.)

Uncaught TypeError: Cannot read property 'ImageRoute' of undefined

I have a simple set of components that all are composed of the following main component. The document component exposes its event handler from its props property. The event fires all the way up as expected. However once its caught in the main component, i try to set the state. Upon setting the state inside the event handler it throws an error the first time i try and retrieve the state. Every subsequent attempt works as expected.
In the example image below it shows the first time i set and try to print out the value of ImageRoute from the document object it fails then works every single time after.
selectedDocument is the eventhandler
Anybody have an explanation?
var Workstation = React.createClass({
getInitialState: function () {
return {};
},
selectedDocument :function(obj, clickedNumber){
var component = this;
console.log(obj.ImageRoute)
console.log(clickedNumber + " was clicked")
component.setState({ selectedDocument: obj });
console.log("selectedDocument set")
if (this.isMounted()) {
console.log(this.state.selectedDocument.ImageRoute)
} else {
console.log("not mounted")
}
},
render: function () {
return (
<div>
<DocumentQueue initialData={jsonData.initialData} selectedDocument={this.selectedDocument} />
<ImageViewer src={this.state.selectedDocument==null ? this.state.selectedDocument : this.state.selectedDocument.ImageRoute} />
</div>
);
}
});
you havent set the state yet. what I mean is the setState function is async and doesn't wait until the state is set before moving to the next line of code. you can use a callback function to set this up correctly
var component = this;
console.log(obj.ImageRoute)
console.log(clickedNumber + " was clicked")
component.setState({ selectedDocument: obj }, function(){
console.log("selectedDocument set")
if (component.isMounted()) {
console.log(component.state.selectedDocument.ImageRoute)
} else {
console.log("not mounted")
}
});

i need React databinding (Arr push after data refresh)

I am faced with the problem
web page is to react with the signal.
Signal does not regularly.
my Scenarios (Arr data push after refresh)
It does not give any one event
Because I can not use. setState funciton
i think javascript function call for react databind refresh
Because the data binding, you use the following dataRefresh() functions.
I know code is incorrect.
I've written code like the following:
var dataArr = [{
key : '1',
text : "hello1",
title: "title1"
},
{
key : '2',
text : "hello2",
title: "title2"
},
{
key : '3',
text : "hello3",
title: "title3"
}
];
var Repeat = React.createClass({
render : function(){
var data = this.props.items;
return(
<PanelGroup accordion >
{ data.map(function(item){
return(
<Panel header={item.title} eventKey={item.key} >
{item.text}
</Panel>
);
})}
</PanelGroup>
);
}
});
function startReact(){
React.render(
<div>
<Repeat items={ dataArr }/>
</div>,
document.getElementById('content')
);
}
startReact();
function dataRefresh(){
dataArr.push({
key : '4',
text : "hello4",
title: "title4"
});
startReact();
}
setTimeout("dataChange()",3000);
It is the question.
I need to have an idea that can solve the problem.
Advice is required.
That's a bad idea. When you have new data use setState so it will update/rerender your view automatically that's the point of react.
Bind your update to a function that update the state not directly to the render.
Here is an example very easy it explain how to update your state when the user is clicking on some button:
https://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
So for your instead of handling a user action you'll set an handler that is called when you have new data.
I hope it's clear
To go in React way, you must use state instead of that above method.
Use getInitialState to point to the global dataArr and then use setState to update the state.
Even I would suggest putting dataArr in the base component holding the child components. This will avoid polluting the global namespace as well.
Inside your setTimeout, avoid using string. instead wrap it inside a function like below:
setTimeout(function() {
dataChange();
}, 3000);
So the code will become:
var Repeater = React.createClass({
getInitialState: function() {
return {
data: dataArr
}
},
componentDidMount: function() {
setTimeout(function() {
// update the dataArr
// Instead of calling dataChange gloabl method, I would put it inside the base component and call this.updateData();
// this.setState({data: dataArr});
}.bind(this),3000);
},
updateData: function() {
// increment the array and call
this.setState({data: dataArr});
},
render : function() {
return (
<div>
<Repeat items={ this.state.data}/>
</div>
);
}
});
The below code will become:
function startReact(){
React.render(<Repeater />,
document.getElementById('content')
);
}

Resources