I am looking to create a one page application with ReactJS.
Is it advisable to combine it with angular or it is suitable just on its own? I would like to populate the one page site with sections - adding various features like carousels, sliders, isotope filters ...
<!DOCTYPE html>
<html>
<head>
<title>React Js one page</title>
<script src="https://fb.me/react-with-addons-0.14.7.min.js"></script>
<script src="https://fb.me/react-dom-0.14.7.min.js"></script>
</head>
<body>
<section>
One
<script>
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>;
}
});
ReactDOM.render(<HelloMessage name="Colonel Mustard" />, mountNode);
</script>
</section>
<section>
Two
<script>
var CommentBox = React.createClass({
render: function() {
return (
<div className="commentBox">
Hello, world! I am a CommentBox.
</div>
);
}
});
ReactDOM.render(<CommentBox />, mountNode);
</script>
</section>
<section>
Three
<script>
"use strict";
var MarkdownEditor = React.createClass({
displayName: "MarkdownEditor",
getInitialState: function getInitialState() {
return { value: 'Type some *markdown* here!' };
},
handleChange: function handleChange() {
this.setState({ value: this.refs.textarea.value });
},
rawMarkup: function rawMarkup() {
return { __html: marked(this.state.value, { sanitize: true }) };
},
render: function render() {
return React.createElement(
"div",
{ className: "MarkdownEditor" },
React.createElement(
"h3",
null,
"Input"
),
React.createElement("textarea", {
onChange: this.handleChange,
ref: "textarea",
defaultValue: this.state.value }),
React.createElement(
"h3",
null,
"Output"
),
React.createElement("div", {
className: "content",
dangerouslySetInnerHTML: this.rawMarkup()
})
);
}
});
ReactDOM.render(React.createElement(MarkdownEditor, null), mountNode);
</script>
</section>
</body>
</html>
If you're just starting out with React, I'd highly recommend following Pete Hunt's advice:
You’ll know when you need Flux. If you aren’t sure if you need it, you don’t need it.
The best thing to do is get started with React by itself and manage application state using the local state that comes with each of your components.
When you find that you start having to pass data back up to parent components, then add Flux into the mix and rewrite your stateful components to instead use Flux stores.
We'll look at how to tackle writing a simplified version of the StackOverflow answer component as a React application from the bottom up.
Notice, I said React application, not React component. This is because there's no technical difference. A React application is a big React component made up of lots of smaller ones.
Identify Components
Once you have an interface for your application (anything from wireframes to html/css) you can visually subdivide them to work out how they'll fit together as React components.
There are no hard and fast rules about how exactly you decide what should or should not be it's own component, but you'll get a feeling for it the more times you do it.
is <Answer />
is <Votes />
is <AnswerText />
is <AnswerActions />
Because we're building from the bottom up, we'd start by implementing each of the child components and testing that they work alone.
At this point in the development lifecycle we'd just write static markup for each component. There's no need to think about props or state yet.
We can use the stateless component syntax to get started on the components we've identified. Here's an example of how we might write the <Votes /> component.
function Votes() {
return (
<div>
<a>▲</a>
<strong>0</strong>
<a>▼</a>
</div>
);
}
Of course this doesn't do anything, but it allows us to start composing our components to get a feel for the structure of the application.
We can render this into the DOM to check that it works at any time.
ReactDOM.render(<Votes />, document.getElementById('app'));
Once you'd finished implementing static versions of the other components, you could put them together to create the parent <Answer /> component.
function Answer() {
return (
<div>
<Votes />
<AnswerText />
<AnswerActions />
</div>
);
}
Design Data Flow
The next thing to do is to figure out how data flows through your application.
At this point we can create some dummy data in the form of an answer object that looks something like this:
{
"id": 0,
"votes": 0,
"text": "This is an answer"
}
Initially we can render the <Answer /> component by passing this answer object to it as a prop.
<Answer answer={answer} />
Now it's that components job to pass down the appropriate data to its children.
Obviously not each child needs all of the data though, so we'll have to decide what data goes where. Let's update our <Answer /> component.
function Answer(props) {
var answer = props.answer;
return (
<div>
<Votes id={answer.id} count={answer.votes} />
<AnswerText text={answer.text} />
<AnswerActions id={answer.id} />
</div>
);
}
The <Votes /> component needs know the current number of votes and it also needs to know the id of the answer so that it can communicate change to the server.
The <AnswerText /> component just renders a block of text, so that's all we need to pass it.
Finally, the <AnswerActions /> component renders a list of links that allow the user to perform some action (share, edit, flag) on the answer. This component also needs the answer's id so that it can communicate with the server.
Now we have to update these child components in turn to use these new dynamic values, instead of the static values we used at first. We'll revisit the <Votes /> component to see this happen.
function Votes(props) {
var urls = {
upvote: '/api/answers/' + props.id + '/upvote',
downvote: '/api/answers/' + props.id + '/downvote'
};
return (
<div>
<a href={urls.upvote}>▲</a>
<strong>{props.votes}</strong>
<a href={urls.downvote}>▼</a>
</div>
);
}
Now our vote component will make a HTTP request to the appropriate endpoint when we click on the vote buttons, however, we'd rather make this update without reloading and re-rendering the entire application.
Identify Stateful Components
The final piece of the component development process is to identify stateful components. These components have moving parts and data that will change during the lifetime of the application.
Each time the state inside a component changes, the entire component re-renders. We can revisit the wireframes to see which of our components needs to manage changing data.
This application only has one stateful component () and that's `. When we click on one of the arrows, we need to update the number to reflect the new count.
It's the only one of our components that ever needs to re-render.
This means we'll need to upgrade the component to use React's createClass syntax. This allows it to start managing it's own state.
var Votes = React.createClass({
getInitialState: function() {
return { votes: this.props.votes };
},
upvote: function() {
var newVotes = this.state.votes + 1;
this.setState({
votes: newVotes
});
},
downvote: function() {
var newVotes = this.state.votes - 1;
this.setState({
votes: newVotes
});
},
render: function() {
return (
<div>
<a onClick={this.upvote}>▲</a>
<strong>{this.state.votes}</strong>
<a onClick={this.downvote}>▼</a>
</div>
);
}
});
I've jumped the gun a bit and implemented the full component, but hopefully you'll get the idea.
First we use getInitialState to set up some state to represent the initial number of votes in the component.
Next we implement upvote and downvote component methods that update the component state.
Finally we re-implement the render method from before, but have the arrows trigger the new component methods, not page requests.
Each time we make a call to setState, React will re-render the component. Hopefully you can see why we put the state in the <Votes /> component and not the <Answer /> component. It would be crazy to re-render the answer text and actions, just because the votes had changed.
Flux It Up
Once we've identified and implemented all of our stateful components, we can start to move their state out into Flux stores.
It's much more likely that a real application would have an <AnswerStore /> than a <VoteStore />, so that's what we'll implement. For now we'll just keep mocking our data.
var AnswerStore = {
_listeners: [],
_answers: {
"0": {
"id": 0,
"votes": 0,
"text": "This is an answer"
}
},
get: function(id) {
return this._answers[id];
},
update: function(id, update) {
var answer = this.get(id);
var updatedAnswer = Object.assign({}, answer, update);
this._answers[id] = updatedAnswer;
this.emit();
},
listen: function(f) {
this._listeners.push(f);
},
emit: function() {
this._listeners.forEach(function(f) {
f();
});
}
};
In this example, I've written a fairly generic store that contains data, provides simple handlers for listening to model changes and finally exposes methods for mutating the data in the store.
It's important that our update method treats the individual answers as immutable in this application, otherwise we risk mutating an object that other parts of the application have a reference to, causing the object to change underneath them. We use Object.assign to create a new object each time, based on the old one.
The next thing we need to do is set up some action handlers for this store.
dispatcher.register(function(action) {
switch(action.type) {
case 'UPVOTE':
var votes = ActionStore.get(action.id);
ActionStore.update(action.id, { votes: votes + 1 });
break;
case 'DOWNVOTE':
var votes = ActionStore.get(action.id);
ActionStore.update(action.id, { votes: votes - 1 });
break;
}
});
This simply wires the update method to two actions called 'UPVOTE' and 'DOWNVOTE'
Now we connect Flux to our <AnswerComponent /> which needs to be re-written in the long form.
var Answer = React.createClass({
getInitialState: function() {
return { answer: {} };
},
componentWillMount: function() {
this.update();
AnswerStore.listen(this.update);
},
update: function() {
var id = this.props.id;
this.setState({ answer: AnswerStore.get(id) });
},
render: function() {
var answer = this.state.answer;
return (
<div>
<Votes id={answer.id} count={answer.votes} />
<AnswerText text={answer.text} />
<AnswerActions id={answer.id} />
</div>
);
}
});
In our componentWillMount method we fetch our initial data for the store, then set up a listener on the store that fetches and updates the component state, whenever the store changes.
Finally, we need a way to dispatch the appropriate actions from our <Votes /> component.
The most popular way to do this is with action creators. An action creator is a function which takes some data as parameters, then packages it up and dispatches it as an action.
var Actions = {
upvote: function(id) {
dispatcher.dispatch({
type: 'UPVOTE',
id: id
});
},
downvote: function(id) {
dispatcher.dispatch({
type: 'DOWNVOTE',
id: id
});
}
};
Then we call these actions from inside our <Votes /> component (which can become stateless again).
function Votes(props) {
var id = props.id;
return (
<div>
<a onClick={Actions.upvote.bind(null, id)}>▲</a>
<strong>{props.votes}</strong>
<a onClick={Actions.downvote.bind(null, id)}>▼</a>
</div>
);
}
This component now uses the action creators to dispatch actions for our Flux store(s) to handle.
If we look at the flow of data through our application, we can see that we now have a unidirectional cycle, rather than a tree.
The <Answer /> component passes the id down to the <Votes /> component.
The <Votes /> component dispatches an action using that id.
The AnswerStore processes the action and emits a change.
The <Answer /> component hears the update and updates its state, re-rendering its children.
Here's a jsfiddle of this demo application.
Scale Up
This is a very simple component that only handles a tiny amount of data flow and even less application state, however, it's enough to show you how to compose a React component and that's all you need to build a React app.
Let's imagine we were implementing a StackOverflow question as a React application.
function App() {
return (
<Page>
<Navigation />
<SideBar>
<MetaDetails />
<Ads />
<RelatedQuestions />
</SideBar>
<Question />
<AnswerList />
<AnswerEditor />
<Footer />
</Page>
);
}
It might seem like a complex application, but you can break it down and express it as distinct components, then you can implement and test the components individually, just like we did here and bring them altogether to form a complex application.
Don't Over Complicate
For most simple React applications like this one, Flux is not actually necessary. It's worth remembering that React was released over a year before Flux and yet it was adopted by a lot of developers regardless.
Of course, I've only really covered structuring and implementing components here. Taking an application from wireframes to deployment is a much more complicated process and there's no way it could be covered in detail in one answer. In time, you'll probably also want to learn about:
Package management and dependencies
Module bundlers
Routing
Hot Reloading
ES6/Babel
Redux
Server Side Rendering
Immutable Data
Inline Styles
Relay/Falcor/GraphQL
It takes some time to get through this list of things, the trick is not to rush. Don't overcomplicate your existing project until you find the reasons that these solutions exist, naturally.
I think react-howto is the best guide out there. Although it's not heavy on detail, it links to a lot of good resources and most importantly it provides an opinionated guide to the order in which you should learn these technologies on your way to becoming a competent ReactJS developer.
The choice of framework (Angular/React) does not prevent building any of the functionality you described, and your site could be built with neither, either, or both of those frameworks.
While you certainly could combine Angular and React, I'm not sure why you would want to, and it's not going to be the easiest of tasks. It's doable, of course, but it's going to provide a lot of difficulty for very little ultimate gain.
If you want to build a SPA with React, I would focus more on finding a Flux implementation that you like, and learning how to integrate that. Flux is designed specifically with React in mind to handle large SPAs which might have complicated data flow, and it's certainly a tool that is easier to incorporate early on.
The only other library I would consider out of the gate would be Immutable.js, which pairs very well with both React and Flux.
But otherwise, until you find a need to bring in additional frameworks/libraries, attempt to hold off. With all of the exciting JS frameworks out there, it's tempting to want to use them all, but in reality you're better off picking one to focus on, and then maybe bringing in some tools from another later on when they are necessitated.
I am currently learning react and I have run into the problem of elegently extracting states from my components.
basically I have a few components which contains forms and other inputs from which I need the data in my business logic, the data I need is coupled with the state of the component. From what I understand the data should have unidirectional flow but I can't think of how I can make my data flow back towards my business logic. I could just make some interface functions which call the respective, but I feel this would violate the unidirectional flow.
anyhelp with some examples would be greatly appreciated!
You typically pass down callbacks from parent components to child components as props. When the state changes in any of the child components, it invokes that callback and passes whatever data is appropriate in each use case. Your "controller-view" (the root component that implements the actual callback) then does whatever business logic you need based on the current state and then updates its state accordingly (causing a re-render of the component tree from that component down). Read the docs about component communication.
Something like this:
var Child = React.createClass({
onTextChange: function() {
var val = 13; // somehow calculate new value
this.props.onTextChange(val);
},
render: function() {
return <input type="text" value={this.props.val} onChange={this.onTextChange} />
}
});
var Parent = React.createClass({
onTextChange: function(val) {
var newVal = someBusinessLogic(val);
this.setState({val: newVal});
},
render: function() {
return <Child onTextChange={this.onTextChange} val={this.state.val} />
}
});
The best way to work with data flow in React is to use the Flux pattern. You need some time to understand how it works, but it will make your life much easier as your project grows.
Look at some Flux tutorial, for example this one (using the Alt flux implementation): https://reactjsnews.com/getting-started-with-flux/
I'm working on a project using React.js, and very confused about the composition of React.
http://facebook.github.io/react/docs/multiple-components.html
the link above gives an example. It uses React.creatClass() create three components. A parent component and two child components. The parent component includes the others within it's JSX in the render method.
This example's very clear, but not very 'reusable'. What if I wanna pass in another child in another situation? React.js seems lacking the 'extend' method like Backbone's view.
later, I found that you can pass children components in the React.render(), and use this.props.children to composite.
var Tom = React.createClass({
render: function(){
return(
<a>This is Tom.</a>
)
}
});
var John = React.createClass({
render: function(){
return(
<a>This is John.</a>
)
}
});
var Outter = React.createClass({
componentDidMount:function(){
console.log(this.props.children);
},
render: function(){
return(
<div className="test">
{this.props.children}
</div>
)
}
});
React.render(<Outter><Tom /><John /></Outter>, document.getElementById('main'));
I think that's great but what's the really difference between this method and the example above? is this method the right way to composite components in React.js?
thanks
The difference is just like you said, that you can pass any components you'd like as children of that component. Components that use this.props.children are usually components that acts as wrappers for style and behaviour, but the contents of the component changes for different use cases. Like a popup, where you want the same look and behaviour (like a close button) for every popup, but the contents of the popup is different for every popup.
Components that don't use this.props.children are more like black boxes, they know everything about how they should be rendered and what child components they need. But you can still make them dynamic by passing other props to them.
Components can be also be passed as props. Components are just JS objects, and any JS object can be passed as a prop. But I don't think I've ever seen a use case for doing it. It might make some sense if you have a wrapper component with two or more specific "slots" that should be rendered to. Something like:
var Wrapper = require('./wrapper');
var Header = require('./title');
var Content = require('./content');
var Footer = require('./footer');
var MyComponent = React.createClass({
render() {
return <Wrapper footer={Footer} header={Header} content={Content} />;
}
});
It depends on your use-case, take this two examples of forms:
a login form - almost all login forms have the same structure, username/email, password, a keep me logged in checkbox, and a login button; a LoginForm component doesn't need to be further customised in regards to its structure so it's suitable to be used as is
a signup form - now depending on context you might give more or less fields to the user to complete when signing up, and in this case you use props.children
Now I understand the concept of stores as the source of truth for a React app, but it seems that sometimes using stores is overkill, especially in UI-only situations.
For example, say I'm making an app which contains a list of movies. The app contains a search bar which lets you filter these movies according to their title. Should the value of this search bar (let's call it searchTerm) be contained in a store? Its only impact is on the list of movies shown, which is purely a UI feature. It won't be sent to the server or saved to local storage. So in my handleTextChange function, should I alert a store, or simply set the component's state:
Should it be this (using a store):
var Actions = Reflux.createActions([
"searchChanged"
]);
var Store = Reflux.createStore({
listenables: [Actions],
getInitialState: function () {
return data;
},
onSearchChanged: function (searchTerm) {
this.trigger(data.filter(function (el) {
return el.name.toLowerCase().indexOf(searchTerm.toLowerCase()) != -1;
}));
}
});
var View = React.createClass({
mixins: [Reflux.connect(Store, "movies")],
handleTextChange: function (e) {
Actions.searchChanged(e.target.value);
},
render: function(){
//Render here. Somewhere there is this input element:
<input onChange={this.handleTextChange} type="text"/>
}
)};
or this (not using a store):
var Store = Reflux.createStore({
getInitialState: function () {
return data;
},
});
var View = React.createClass({
mixins: [Reflux.connect(Store, "movies")],
handleTextChange: function (e) {
this.setState({searchTerm: e.target.value});
},
render: function(){
var filtered = this.movies.filter(function (el) {
return el.name.toLowerCase().indexOf(this.state.searchTerm.toLowerCase()) != -1;
});
//Render here using the filtered variable. Somewhere there is this input element:
<input onChange={this.handleTextChange} type="text"/>
}
}
The latter example is obviously simpler. Is there a good reason to use a store to filter the data? Or should the view have a searchTerm variable and perform the filtering in the render() function?
As your examples indicate, not using a store is simpler, and arguably correct in this case.
A weak question to answer is:
Does any other component need to know about the search results?
A better question is:
Might some other component need to know about the search results?
Consider that if you add paging through results, or even a simple header of "12 results found", then those components need to know the result and will need to get it from the store. Or perhaps you'll want to add a router and have the search update the url and the url change to drive the app.
If you can say for certain that ONLY subcomponents will ever care about a value, then state is OK.
Both approaches are correct! But for your situation, filtering in component is better. Because searching result is calculable. The store should just keep the original data. The book "Developing the React edge" has an example for filterableForm, keep the search keyword in the view component is perfectly fine.
I've recently started using ReactJS in my UI projects which has greatly simplified my UI workflow. Really enjoyable API to work with.
I've noticed recently that I've had to use a pattern in a couple of my projects that needed to aggregate data on a page. This data would live in the DOM and not be dependent on using the React state for data transitions.
This is an example implementation:
var Component = module.exports = React.createClass({
componentDidMount: function() {
this.component = new Component();
this.component.start();
},
componentWillUnmount: function(prevProps, prevState) {
if (this.component !== undefined) {
this.component.destroy();
}
},
render: function() {
return (
<div id="componentContainer"></div>
);
}
});
var Component = function(){
// Some object that dynamically loads content in a
// pre-packaged NON-react component into componentContainer
// such as a library that renders a graph, or a data loader
// that aggregates DOM elements using an infinite scroll
}
My question is whether or not this is the proper way to aggregate data into the DOM using React. I looked around for the idiomatic way of doing this, but my google-foo was unable to come up with anything.
Thanks!
EDIT - as a side note, does anyone think there will be a problem with the way I destroy the container, using the componentWillUnmount?
The main problem is that you're using an id, which is inflexible and makes assumptions about the rest of the components (because ids must be globally unique).
module.exports = React.createClass({
componentDidMount: function() {
// pass a DOM node to the constructor instead of it using an id
this.component = new Component(this.getDOMNode());
this.component.start();
},
componentWillUnmount: function() {
this.component.destroy();
},
render: function() {
return <div />;
}
});
Your componentWillUnmount was fine, but the one place you set this.component will always run before componentWillUnmount, and there's no other reason it'd be assigned/deleted, so the if statement isn't needed.
Also the arguments both weren't used, and aren't provided to componentWillUnmount. That signature belongs to componentDidUpdate.