Communication between Components - reactjs

Here's my situation, I'm very new to react/flux, and just started to play around with it. My toy project is a simple library app. My current state is as follows:
i have a component called Login. This component is responsible only to store the currently "logged in" user to be able to deal with latter Borrow/Return buttons in the library. So the user inputs it's name which will be saved into session storage at the moment.
my another component is called Library which holds the main logic of my app.
I'm struggling to find out how to re-render my library component if i change the current user. Since its my first project, I don't want to play around with proper authentication, or create a router. So I simply made a Login form and whenever the user input's his name, and logs in, i render the library app onto the DOM.
Login = React.createClass({
_handleSubmit: function () {
var inp = this.refs.login.getDOMNode();
sessionStorage.setItem("username", inp.value);
console.info('User Credentials saved to SessionStorage');
inp.value = '';
React.renderComponent(
<Library />,
document.querySelector('#content')
);
},
render: function () {
return (
<div className="panel panel-default">
blabla
<button className="btn btn-default" type="button" onClick={this._handleSubmit} >
Login
</button>
blabla
</div>
);
}
});
This works well, but i think it's far from an optimal approach. Whenever i Login again, react is re-rendering a new instance from the Library component into the DOM node. I'm not dealing with destructuring at all, and I think it's bad :( I know react will not append, but erase and fill into the node, but the event handlers will possibly remain etc.
So what could be a possible good solution for my situation?
I have 3 possible solutions in my mind
Either i should develop an event system to be able to notify the Library component if I re-login with a different user to re-render itself, or
I could build up a parent-child relationship upon Login & Library, so when i modify the state of the Login component my Library app would re-render too.
Call an Action which would update the component
Stick with current
:) Thanks for any answer,
Cheers
Hint:
app.js
'use strict';
var React = require('react'),
Login = require('./components/Login.jsx');
// Dev-tools
window.React = React;
React.renderComponent(
Login(),
document.querySelector('#login')
);
Login.jsx
mentioned upper
Library.jsx
/** #jsx React.DOM */
'use strict';
var React = require('react'),
BookShelf = require('./BookShelf.jsx'),
Store = require('../stores/Store'),
Library;
/**
* Gets state from Storage
* #returns {{books: BookCollection, users: UserCollection, categories: CategoryCollection}}
*/
function getState() {
var state = Store.getAll();
return {
books: state.books,
users: state.users,
categories: state.categories
};
}
Library = React.createClass({
getInitialState: function() {
return getState();
},
componentDidMount: function() {
Store.addChangeListener(this._onChange);
Store.initialize();
},
componentWillUnmount: function() {
Store.removeChangeListener(this._onChange);
},
_onChange: function() {
this.setState(getState());
},
render: function() {
return (
<div>
<BookShelf
books={this.state.books}
users={this.state.users}
categories={this.state.categories}
/>
</div>
);
}
});
module.exports = Library;

If this is a Flux app, then you want to take all that application logic and application state and move it into a store (or multiple stores).
Right now, it looks like you're doing that just fine for things related to the library. I would rename that store LibraryStore. But you probably want an AppStore or a UserStore or a SessionStore or something that has the logic and data related to the login state, current user, and auth token.
So then once the user logs in, yes you would want to create an Action (option #3) to let all the different stores in you app know that your user has logged in, but primarily to inform the AppStore. Then your top-level controller-views can listen to AppStore and decide what to display. If you're using React's event model, you don't need to worry about cleaning up the event handlers. Flux controller-views don't use the React model, so we have to cleanup those on unmounting.
Part of your difficulty may be coming from simulating processes that are async. Authentication, for example, will require a server call, and your new action would be created in the success/error callback to that call. To simulate this against localStorage, you might make a sync query of the storage and then call one of two different actions for success/failure.

Related

Best way to get HTTP data and handle a 404?

I am fairly new to React so I don't know the best ways to get data. I have a page URL like /country/japan and this is my component:
var Country = React.createClass({
componentDidMount: function() {
var _this = this,
country = _this.props.params.country;
Axios.get('http://URL/?search=' + country)
.then(function(result) {
_this.setState({
country: result.data[0]
});
});
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
var country = this.state.country;
return (
<div>
<h1>{country.name}</h1>
</div>
);
}
});
I cannot seem to access the country data. What's the proper way to do this? Also how would you trigger a 404?
I would say first understand the difference between presentational and container components.
Presentational components:
Are concerned with how things look.
May contain both presentational and container components inside, and usually have some DOM markup and styles of their own. Often allow containment via this.props.children.
Have no dependencies on the rest of the app, such as Flux actions or stores.
Don’t specify how the data is loaded or mutated.
Receive data and callbacks exclusively via props.
Rarely have their own state (when they do, it’s UI state rather than
data).
Are written as functional components unless they need state,
lifecycle hooks, or performance optimizations.
Examples: Page, Sidebar, Story, UserInfo, List.
Container components:
Are concerned with how things work.
May contain both presentational and container components** inside but
usually don’t have any DOM markup of their own except for some
wrapping divs, and never have any styles.
Provide the data and behavior to presentational or other container
components.
Call Flux actions and provide these as callbacks to the
presentational components.
Are often stateful, as they tend to serve as data sources.
Are usually generated using higher order components such as connect()
from React Redux, createContainer() from Relay, or Container.create()
from Flux Utils, rather than written by hand.
Examples: UserPage, FollowersSidebar, StoryContainer,
FollowedUserList.
You can check more here. This would help you understand how to trigger an api call(it should be in containers).
So now coming to your code. I would say move your api code to the container and call your component inside the container.
var CountryContainer = React.createClass({
componentDidMount: function() {
var _this = this,
country = _this.props.params.country;
axios.get('http://URL/?search=' + country)
.then(function(result) {
//200-300 response codes
//update you state here with say variable data
.catch(function(error){
//400+ response codes
}
});
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return (
<Country data={this.state.data} />
);
}
});
I would suggest you go to over axios documentation. They have clearly mention when the API call fails and how to handle it :)

ReactJS render() method called more often than necessary in complex RefluxJS application

I have a RefluxJS application which has several stores and a pretty deep component hierarchy. I've tried to make the components very independent, with each connecting to the stores it needs to render; and the stores themselves sometimes call Actions that other stores listen to.
I've found that I get a lot of spurious calls to my components' render() methods, because two stores might listen to the same action, and different components in the hierarchy might listen to those different stores. This is affecting the user experience because sometimes there's a little bit of lag.
Here's some code:
var Actions = Reflux.createActions(['changeUser']);
Actions.changeUser.preEmit = () => console.log('Action emit: changeUser');
var UserStore = Reflux.createStore({
listenables: [Actions],
onChangeUser(user) {
this.trigger(user);
}
});
var MessageStore = Reflux.createStore({
listenables: [Actions],
onChangeUser(user) {
setTimeout(() => {
// pretend we had to go to an API or something to get this
var message = "Welcome to the app!";
this.trigger(message);
}, 500);
},
});
var App = React.createClass({
mixins: [Reflux.connect(UserStore, 'user')],
render() {
console.log('Component render: App');
if (!this.state.user) {
return (
<button onClick={() => Actions.changeUser('Some User')}>
Click to make stuff happen
</button>
);
}
return (
<div>
<div>Hello, {this.state.user}.</div>
<Message / >
</div>
);
}
});
var Message = React.createClass({
mixins: [Reflux.connect(MessageStore, 'message')],
render() {
console.log('Component render: Message');
return <div>Your message: {this.state.message}</div>;
}
});
ReactDOM.render( <App/> , document.getElementById('app'));
Fiddle: https://jsfiddle.net/9xwnxos6/
This is way oversimplified (in this example I'd probably just add a loading indicator of some kind), but illustrates the basic issue that you can see the UI sort of transitioning through intermediate states while you're doing things.
How can I improve my React/Reflux design in order to avoid multiple renders triggering from a single interaction?
It seems my issues are coming from violating a couple of good React/Flux practices:
Don't trigger Actions from within a Store
Only connect to Stores in high-level components
I am refactoring to get the Store connections out of the low-level components. I'm not crazy about this, because it means I have to pass all kinds of props through these deep component hierarchies to get them where they need to be. But it seems that is the "right" way to build a Reflux app.
If no one else posts an answer within the next few days, I will accept this one.

Full stack ReactJS suite

As ReactJS is only view layer and works by his own, which additional libraries to use for for full stack ReactJS suite - data layer, comunication with server (AJAX calls, REST), etc. when building SPA (single page application)?
Are they any ReactJS full stack frameworks (something like AngularJS) available?
ReactJS alone gives you DOM rendering, but Facebook also created Flux which gives you an architecture in which to work. By following the rules set out by Flux, you now have a SPA with DOM rendering, data models, and communication between the two.
Of course, the SPA that you'll build with Flux is self-contained. Flux does not go so far as to provide you with tools to perform AJAX requests. You will need another library for that. However, the NodeJS community is so full of AJAX implementations, I might actually prefer it.
superagent is a pretty popular one. (It's what I use.) You might notice it doesn't support promises, so you might also check out superagent-bluebird-promise, which wraps superagent with the bluebird promise library.
Another note, if you're going to use Flux, I recommend also pulling in one of the growing number of wrapper libraries that will help you reduce the boilerplate. Check out Reflux.
A full cycle might look like this...
RecordList.jsx
const React = require('react');
const Reflux = require('reflux');
const RecordStore = require('../stores/RecordStore');
const RecordActions = require('../actions/RecordActions');
const RecordList = React.createClass({
mixins: [
// auto-magically create event listeners to state change to re-render
Reflux.connect(RecordStore)
],
// There is no `getInitialState()` here, but the one in `RecordStore` is inherited.
// load the initial data
componentDidMount: function () {
RecordActions.load();
},
// render records as a list
render: function () {
return (
<li>
{
this.state.records.map(function (record) {
return <ul>{record.name}</ul>;
})
}
</li>
);
}
});
module.exports = RecordList;
RecordActions.js
const Reflux = require('reflux');
const request = require('superagent-bluebird-promise');
const RecordActions = Reflux.createActions({
// create an action called 'load' and create child actions of 'completed' and 'failed'
load: {asyncResult: true}
});
// set up promise for loading records
RecordActions.load.listenAndPromise(() =>
request.get('/records')
.type('application/json')
.then(res => res.body)
);
module.exports = RecordActions;
RecordStore.js
const Reflux = require('reflux');
const RecordActions = require('../actions/RecordActions');
/**
* storage for record data
*/
const RecordStore = Reflux.createStore({
// listen for events from RecordActions (Reflux)
listenables: RecordActions,
init: function () {
this.data = {
records: []
};
},
// facilitate initializing component state with store data
getInitialState: function () {
return this.data;
},
/*
* all records
*/
getRecords: function () {
return this.data.records;
},
// handle successful load of records
onLoadCompleted: function (response) {
this.data.records = response;
this.trigger(this.data);
},
// handle failure to load records
onLoadFailed: function (err) {
console.error('Failed to load records', err.toString());
}
});
module.exports = RecordStore;
U could look at
http://martyjs.org/ which is an implementation of the Flux Application Architecture.
(es6 support/React native support/ Higher order components (containers: https://medium.com/#dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750))
You may want to search on GitHub for "react starter kits". A popular technology stack for building SPAs with React consists of:
a Flux implementation -> you can choose one from here https://github.com/voronianski/flux-comparison
React Router https://github.com/rackt/react-router
Webpack + Webpack Dev Server, Babel, Gulp, ESLint + CSSLint, LESS / Sass etc.
Jest / Mocha + Chai + Sinon
Netflix Falcor https://github.com/Netflix/falcor (developer preview)
some React components http://material-ui.com / https://react-bootstrap.github.io / http://react-components.com
As for starter kits, here's an interesting list of React boilerplates http://habd.as/awesome-react-boilerplates
You could also check MERN (MongoDB, Express, ReactJS, NodeJs) full stack at mern.io. I have been using it and it has been awesome stack. It comes with Webpack, Redux and React-Router and other basic frameworks.

Setting the initial state in React components for progressive enhancement & Flux architecture

I've read on http://scotch.io/tutorials/javascript/build-a-real-time-twitter-stream-with-node-and-react-js and it describes a technique of taking over server rendered React components seamlessly:
Server renders into {{{markup}}} in handlebars, and pass initial state.
<section id="react-app">{{{ markup }}}</div>
<script id="initial-state" type="application/json">{{{state}}}</script>
Then on the client side javascript
/** #jsx React.DOM */
var React = require('react');
var TweetsApp = require('./components/TweetsApp.react');
// Snag the initial state that was passed from the server side
var initialState = JSON.parse(document.getElementById('initial-state').innerHTML)
// Render the components, picking up where react left off on the server
React.renderComponent(
<TweetsApp tweets={initialState}/>,
document.getElementById('react-app')
);
But in a flux architecture, such as described in this article http://scotch.io/tutorials/javascript/creating-a-simple-shopping-cart-with-react-js-and-flux, state is initialized in the getInitialState lifecycle method:
// Method to retrieve state from Stores
function getCartState() {
return {
product: ProductStore.getProduct(),
selectedProduct: ProductStore.getSelected(),
cartItems: CartStore.getCartItems(),
cartCount: CartStore.getCartCount(),
cartTotal: CartStore.getCartTotal(),
cartVisible: CartStore.getCartVisible()
};
}
// Define main Controller View
var FluxCartApp = React.createClass({
// Get initial state from stores
getInitialState: function() {
return getCartState();
},
// Add change listeners to stores
componentDidMount: function() {
ProductStore.addChangeListener(this._onChange);
CartStore.addChangeListener(this._onChange);
},
// Remove change listers from stores
componentWillUnmount: function() {
ProductStore.removeChangeListener(this._onChange);
CartStore.removeChangeListener(this._onChange);
},
// Render our child components, passing state via props
render: function() {
return (
<div className="flux-cart-app">
<FluxCart products={this.state.cartItems} count={this.state.cartCount} total={this.state.cartTotal} visible={this.state.cartVisible} />
<FluxProduct product={this.state.product} cartitems={this.state.cartItems} selected={this.state.selectedProduct} />
</div>
);
},
// Method to setState based upon Store changes
_onChange: function() {
this.setState(getCartState());
}
});
module.exports = FluxCartApp;
Which one is the right approach to setting state from a progressive enhancement point of view?
Thinking about progressive enhancement I like how flux and react work together.
I am using ReactJS and Flux in my current project and everything is clean and easy. All you have to be aware of is showing some discipline of creating new stores when it really is needed. I dont really like the eventEmitter stuff though. I just trigger my own events which I define in a seperate eventConstants.js file this allows me to have several components listening for different changes on the same store.
This really scales well.
Answering your question:
It does depend about your usecase. Ignoring that rendering an initial page on the server is great for SEO it does only make sence to render on the server if users should all see pretty much the same content. I like to keep client stuff on the client.
I hope this helped you

ReactJS state vs prop

This may be treading that line between answerable and opinionated, but I'm going back and forth as to how to structure a ReactJS component as complexity grows and could use some direction.
Coming from AngularJS, I want to pass my model into the component as a property and have the component modify the model directly. Or should I be splitting the model up into various state properties and compiling it back together when sending back upstream? What is the ReactJS way?
Take the example of a blog post editor. Trying to modify the model directly ends up looking like:
var PostEditor = React.createClass({
updateText: function(e) {
var text = e.target.value;
this.props.post.text = text;
this.forceUpdate();
},
render: function() {
return (
<input value={this.props.post.text} onChange={this.updateText}/>
<button onClick={this.props.post.save}/>Save</button>
);
}
});
Which seems wrong.
Is it more the React way to make our text model property state, and compile it back into the model before saving like:
var PostEditor = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: this.props.post.text
});
},
updateText: function(e) {
this.setState({
text: e.target.value
});
},
savePost: function() {
this.props.post.text = this.state.text;
this.props.post.save();
},
render: function() {
return (
<input value={this.state.text} onChange={this.updateText}/>
<button onClick={this.savePost}/>Save</button>
);
}
});
This doesn't require a call to this.forceUpdate(), but as the model grows, (a post may have an author, subject, tags, comments, ratings, etc...) the component starts getting really complicated.
Is the first method with ReactLink the way to go?
Updating 2016:
React is changed, and explanation "props vs state" became very simple. If a component needs to change data - put it in a state, otherwise in props. Because props are read-only now.
What's the exact difference between props and state?
You can find good explanation here (full version)
Your second approach is more like it. React doesn't care about models so much as it cares about values and how they flow through your app. Ideally, your post model would be stored in a single component at the root. You then create child components that each consume parts of the model.
You can pass callbacks down to the children that need to modify your data, and call them from the child component.
Modifying this.props or this.state directly is not a good idea, because React will not be able to pick up on the changes. That's because React does a shallow comparison of your post prop to determine if it has changed.
I made this jsfiddle to show how data could flow from an outer to an inner component.
The handleClick method shows 3 ways to (im)properly update state:
var Outer = React.createClass({
getInitialState: function() {
return {data: {value: 'at first, it works'}};
},
handleClick: function () {
// 1. This doesn't work, render is not triggered.
// Never set state directly because the updated values
// can still be read, which can lead to unexpected behavior.
this.state.data.value = 'but React will never know!';
// 2. This works, because we use setState
var newData = {value: 'it works 2'};
this.setState({data: newData});
// 3. Alternatively you can use React's immutability helpers
// to update more complex models.
// Read more: http://facebook.github.io/react/docs/update.html
var newState = React.addons.update(this.state, {
data: {value: {$set: 'it works'}}
});
this.setState(newState);
},
render: function() {
return <Inner data={this.state.data} handleClick={this.handleClick} />;
}
});
From React doc
props are immutable: they are passed from the parent and are "owned" by the parent. To implement interactions, we introduce mutable state to the component. this.state is private to the component and can be changed by calling this.setState(). When the state is updated, the component re-renders itself.
From TrySpace: when props (or state) are updated (via setProps/setState or parent) the component re-renders as well.
A reading from Thinking in React:
Let's go through each one and figure out which one is state. Simply
ask three questions about each piece of data:
Is it passed in from a parent via props? If so, it probably isn't
state.
Does it change over time? If not, it probably isn't state.
Can you compute it based on any other state or props in your
component? If so, it's not state.
I'm not sure if I'm answering your question, but I've found that, especially in a large/growing application, the Container/Component pattern works incredibly well.
Essentially you have two React components:
a "pure" display component, which deals with styling and DOM interaction;
a container component, which deals with accessing/saving external data, managing state, and rendering the display component.
Example
N.B. This example is a probably too simple to illustrate the benefits of this pattern, as it is quite verbose for such a straightforward case.
/**
* Container Component
*
* - Manages component state
* - Does plumbing of data fetching/saving
*/
var PostEditorContainer = React.createClass({
getInitialState: function() {
return {
text: ""
};
},
componentWillMount: function() {
this.setState({
text: getPostText()
});
},
updateText: function(text) {
this.setState({
text: text
});
},
savePost: function() {
savePostText(this.state.text);
},
render: function() {
return (
<PostEditor
text={this.state.text}
onChange={this.updateText.bind(this)}
onSave={this.savePost.bind(this)}
/>
);
}
});
/**
* Pure Display Component
*
* - Calculates styling based on passed properties
* - Often just a render method
* - Uses methods passed in from container to announce changes
*/
var PostEditor = React.createClass({
render: function() {
return (
<div>
<input type="text" value={this.props.text} onChange={this.props.onChange} />
<button type="button" onClick={this.props.onSave} />
</div>
);
}
});
Benefits
By keeping display logic and data/state management separate, you have a re-usable display component which:
can easily be iterated with different sets of props using something like react-component-playground
can be wrapped with a different container for different behavior (or combine with other components to build larger parts of your application
You also have a container component which deals with all external communication. This should make it easier to be flexible about the way you access your data if you make any serious changes later on*.
This pattern also makes writing and implementing unit tests a lot more straightforward.
Having iterated a large React app a few times, I've found that this pattern keeps things relatively painless, especially when you have larger components with calculated styles or complicated DOM interactions.
*Read up on the flux pattern, and take a look at Marty.js, which largely inspired this answer (and I have been using a lot lately) Redux (and react-redux), which implement this pattern extremely well.
Note for those reading this in 2018 or later:
React has evolved quite a bit since this answer was written, especially with the introduction of Hooks. However, the underlying state management logic from this example remains the same, and more importantly, the benefits that you get from keeping your state and presentation logic separate still apply in the same ways.
I think you're using an anti-pattern which Facebook has already explained at this link
Here's thing you're finding:
React.createClass({
getInitialState: function() {
return { value: { foo: 'bar' } };
},
onClick: function() {
var value = this.state.value;
value.foo += 'bar'; // ANTI-PATTERN!
this.setState({ value: value });
},
render: function() {
return (
<div>
<InnerComponent value={this.state.value} />
<a onClick={this.onClick}>Click me</a>
</div>
);
}
});
The first time the inner component gets rendered, it will have { foo: 'bar' } as the value prop. If the user clicks on the anchor, the parent component's state will get updated to { value: { foo: 'barbar' } }, triggering the re-rendering process of the inner component, which will receive { foo: 'barbar' } as the new value for the prop.
The problem is that since the parent and inner components share a reference to the same object, when the object gets mutated on line 2 of the onClick function, the prop the inner component had will change. So, when the re-rendering process starts, and shouldComponentUpdate gets invoked, this.props.value.foo will be equal to nextProps.value.foo, because in fact, this.props.value references the same object as nextProps.value.
Consequently, since we'll miss the change on the prop and short circuit the re-rendering process, the UI won't get updated from 'bar' to 'barbar'

Resources