In order to start this tutorial, we’re going to require a running server. This will serve purely as an API endpoint which we’ll use for getting and saving data. In order to make this as easy as possible, we’ve created a simple server in a number of scripting languages that does exactly what we need it to do. You can view the source or download a zip file containing everything needed to get started.
For sake of simplicity, the server we will run uses a JSON file as a database. You would not run this in production but it makes it easy to simulate what you might do when consuming an API. Once you start the server, it will support our API endpoint and it will also serve the static pages we need.
For this tutorial, we’re going to make it as easy as possible. Included in the server package discussed above is an HTML file which we’ll work in. Open up public/index.html in your favorite editor. It should look something like this:
The <div> tags are not actual DOM nodes; they are instantiations of React div components. You can think of these as markers or pieces of data that React knows how to handle. React is safe. We are not generating HTML strings so XSS protection is the default.
Next, update the CommentBox component to use these new components:
Notice how we’re mixing HTML tags and components we’ve built. HTML components are regular React components, just like the ones you define, with one difference. The JSX compiler will automatically rewrite HTML tags to React.createElement(tagName) expressions and leave everything else alone. This is to prevent the pollution of the global namespace.
Let’s create the Comment component, which will depend on data passed in from its parent. Data passed in from a parent component is available as a ‘property’ on the child component. These ‘properties’ are accessed through this.props. Using props, we will be able to read the data passed to the Comment from the CommentList, and render some markup:
Now that we have defined the Comment component, we will want to pass it the author name and comment text. This allows us to reuse the same code for each unique comment. Now let’s add some comments within our CommentList:
Note that we have passed some data from the parent CommentList component to the child Comment components. For example, we passed Pete Hunt (via an attribute) and This is one comment (via an XML-like child node) to the first Comment. As noted above, the Comment component will access these ‘properties’ through this.props.author, and this.props.children.
親のCommentListコンポーネントから子のCommentコンポーネントにいくつかのデータを渡したということに注意してください。例えば、Pete Hunt（属性を通して）とThis is one comment（XMLのような子ノードを通して）を一番目のCommentに渡しました。上記の通り、Commentコンポーネントはthis.props.author、this.props.childrenを通してこれらの「プロパティ」にアクセスします。
Adding Markdown: Markdownを追加する
Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized.
In this tutorial we use a third-party library remarkable which takes Markdown text and converts it to raw HTML. We already included this library with the original markup for the page, so we can just start using it. Let’s convert the comment text to Markdown and output it:
All we’re doing here is calling the remarkable library. We need to convert this.props.children from React’s wrapped text to a raw string that remarkable will understand so we explicitly call toString().
Remember: by using this feature you’re relying on remarkable to be secure. In this case, we pass sanitize: true which tells marked to escape any HTML markup in the source instead of passing it through unchanged.remarkable automatically strips HTML markup and insecure links from the output.
So far we’ve been inserting the comments directly in the source code. Instead, let’s render a blob of JSON data into the comment list. Eventually this will come from the server, but for now, write it in your source:
This component is different from the prior components because it will have to re-render itself. The component won’t have any data until the request from the server comes back, at which point the component may need to render some new comments.
So far, based on its props, each component has rendered itself once. 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 updates, the component re-renders itself.
When the component is first created, we want to GET some JSON from the server and update the state to reflect the latest data. We’re going to use jQuery to make an asynchronous request to the server we started earlier to fetch the data we need. The data is already included in the server you started (based on the comments.json file), so once it’s fetched, this.state.data will look something like this:
Here, componentDidMount is a method called automatically by React after a component is rendered for the first time. The key to dynamic updates is the call to this.setState(). We replace the old array of comments with the new one from the server and the UI automatically updates itself. Because of this reactivity, it is only a minor change to add live updates. We will use simple polling here but you could easily use WebSockets or other technologies.
All we have done here is move the AJAX call to a separate method and call it when the component is first loaded and every 2 seconds after that. Try running this in your browser and changing the comments.json file (in the same directory as your server); within 2 seconds, the changes will show!
With the traditional DOM, input elements are rendered and the browser manages the state (its rendered value). As a result, the state of the actual DOM will differ from that of the component. This is not ideal as the state of the view will differ from that of the component. In React, components should always represent the state of the view and not only at the point of initialization.
Hence, we will be using this.state to save the user’s input as it is entered. We define an initial state with two properties author and text and set them to be empty strings. In our <input> elements, we set the value prop to reflect the state of the component and attach onChange handlers to them. These <input> elements with a value set are called controlled components. Read more about controlled components on the Forms article.
React attaches event handlers to components using a camelCase naming convention. We attach onChange handlers to the two <input> elements. Now, as the user enters text into the <input> fields, the attached onChange callbacks are fired and the state of the component is modified. Subsequently, the rendered value of the input element will be updated to reflect the current component state.
Let’s make the form interactive. When the user submits the form, we should clear it, submit a request to the server, and refresh the list of comments. To start, let’s listen for the form’s submit event and clear it.
When a user submits a comment, we will need to refresh the list of comments to include the new one. It makes sense to do all of this logic in CommentBox since CommentBox owns the state that represents the list of comments.
We need to pass data from the child component back up to its parent. We do this in our parent’s render method by passing a new callback (handleCommentSubmit) into the child, binding it to the child’s onCommentSubmit event. Whenever the event is triggered, the callback will be invoked:
Now that CommentBox has made the callback available to CommentForm via the onCommentSubmit prop, the CommentForm can call the callbackLet’s call the callback from the CommentForm when the user submits the form:
Now that the callbacks are in place, all we have to do is submit to the server and refresh the list:
Optimization: optimistic updates: 最適化: 快適なアップデート
Our application is now feature complete but it feels slow to have to wait for the request to complete before your comment appears in the list. We can optimistically add this comment to the list to make the app feel faster.