...
 
Commits (12)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
const items = 'abcdefghijklmnopqrstuvwxyz01234567890'.split('')
const items = "abcdefghijklmnopqrstuvwxyz01234567890".split("");
// In the render function of BasicComponent, render the following:
// A 'table' element
// With a child 'thead' element
// With a 'tr' component
// With a 'td' component containing the text 'Item'
// With a 'td' component containing the text 'Index'
//
// At the same level as 'thead', add a 'tbody' element
// Inside of the tbody, map through the this.state.items,
// using the function arguments 'item' and 'index', and return:
// A 'tr' element
// With a child component 'Columns', passing the props
// 'item' and 'index' from the map function
class BasicComponent extends React.Component {
state = { items }
state = { items };
render() {
return (
<table>
<thead>
<tr>
<td>Item</td>
<td>Index</td>
</tr>
</thead>
<tbody>
{this.state.items.map((item, index) => (
<tr key={index}>
<Columns item={item} index={index} />
</tr>
))}
</tbody>
</table>
);
}
}
// Define the Columns component, which extends React.Component.
// In the render function, get 'item' and 'index' from props,
// and return:
// A 'div' with two 'td' children elements:
// The first `td' should render `this.props.item`,
// and the second `td` should render `this.props.index`.
class Columns extends React.Component {
render() {
const { item, index } = this.props;
return (
<React.Fragment>
<td>{item}</td>
<td>{index}</td>
</React.Fragment>
);
}
}
// Look at the output of these components in the browser.
// You should see a "header" row with "Item" and "Index",
// but each column is incorrectly rendering inside _just_
// the "Item" section of the table.
//
// This is because instead of correctly rendering the table,
// we're using a 'div' as the parent of `Columns`.
//
// To fix this, replace the opening and closing 'div' with
// React.Fragment. This should fix the 'table' row rendering.
//
// Try the shorthand React.Fragment syntax too, by replacing
// React.Fragment with a simple `<>` and `</>`.
// No changes are needed below this line.
const root = document.getElementById("root");
if (root) { ReactDOM.render(<BasicComponent />, root); }
if (root) {
ReactDOM.render(<BasicComponent />, root);
}
import React from 'react';
import ReactDOM from 'react-dom';
import Basic from './Basic'
import React from "react";
import ReactDOM from "react-dom";
import Basic from "./Basic";
class Application extends React.Component {
state = null
state = null;
componentDidMount() {
var url = 'https://bytesized-training-assets.herokuapp.com/object.json';
var url = "https://bytesized-training-assets.herokuapp.com/object.json";
fetch(url).then(resp => {
resp.json().then(json => this.setState(json));
......@@ -14,11 +14,7 @@ class Application extends React.Component {
}
render() {
// Render the Basic component, passing all of Application's state into
// the component as props. You can do this by using the spread operator
// inside of the component tag:
// <SampleComponent {...this.state} />
return null
return <Basic {...this.state} />;
}
}
......
import React from 'react';
import ReactDOM from 'react-dom';
import React from "react";
import ReactDOM from "react-dom";
// Import omitProps from the 'omitProps' module
import omitProps from "./omitProps";
class Basic extends React.Component {
render() {
......@@ -9,15 +9,10 @@ class Basic extends React.Component {
<div>
<h1>{this.props.class}</h1>
<h2>{this.props.exercise}</h2>
<h3>{this.props.dataRetrieved && 'Data loaded!'}</h3>
<h3>{this.props.dataRetrieved && "Data loaded!"}</h3>
</div>
);
}
}
// Replace the default export by wrapping the component with omitProps,
// which takes two arguments:
// 1) The name of the component
// 2) An array of keys that correspond to the keys you want to omit from props.
// Try omitting 'dataRetrieved'.
export default Basic;
export default omitProps(Basic, ["dataRetrieved"]);
import React from 'react';
import _ from 'lodash';
import React from "react";
import _ from "lodash";
// Create the omitProps higher order component:
// omitProps should be a function with two arguments,
// PassedComponent and OmitProps.
//
// The function should return a class OmitProps that extends
// React.Component. The class should have a render function that:
// 1) Has a prop variable that is set to the result of _.omit,
// passing in this.props and omitProps as the arguments.
// 2) Renders PassedComponent, passing the entire prop object in as props to the component.
// You can do this by using the spread operator inside of the component tag:
// <SampleComponent {...this.state} />
const omitProps = (PassedComponent, omitProps) => {
return class OmitProps extends React.Component {
render() {
const props = _.omit(this.props, omitProps);
return <PassedComponent {...props} />;
}
};
};
// export the higher component as the default export fo this module.
export default omitProps;
import React from 'react';
import React from "react";
import Header from './Header';
// Import the NewPost component from ./NewPost.
// Follow the structure of the other components in
// this section.
import Post from './Post';
import Sidebar from './Sidebar';
import Header from "./Header";
import NewPost from "./NewPost";
import Post from "./Post";
import Sidebar from "./Sidebar";
export default class Blog extends React.Component {
constructor() {
super();
this.state = {
blogTitle: '',
blogAuthor: '',
posts: [],
blogTitle: "",
blogAuthor: "",
posts: []
};
this.addPost = this.addPost.bind(this);
}
componentDidMount() {
const url = 'https://bytesized-training-assets.herokuapp.com/blog.json';
const url = "https://bytesized-training-assets.herokuapp.com/blog.json";
fetch(url).then(resp =>
resp.json().then(json => {
this.setState({
blogTitle: json.blogTitle,
blogAuthor: json.blogAuthor,
posts: json.posts,
posts: json.posts
});
}),
})
);
}
addPost(newPost) {
const {posts} = this.state;
const { posts } = this.state;
const newPosts = [].concat(newPost, posts);
this.setState({posts: newPosts});
this.setState({ posts: newPosts });
}
render() {
const {blogTitle, blogAuthor, posts} = this.state;
const { blogTitle, blogAuthor, posts } = this.state;
/*
Replace the "Placeholder" span by rendering the NewPost component.
......@@ -52,14 +48,16 @@ export default class Blog extends React.Component {
return (
<div>
<Header blogTitle={blogTitle} blogAuthor={blogAuthor} />
<div style={{width: '100%'}}>
<span>Placeholder</span>
<div style={{ width: "100%" }}>
<NewPost addPost={this.addPost} />
</div>
<div style={{display: 'flex'}}>
<div style={{width: '75%'}}>
{posts.map((post, index) => <Post key={index} post={post} />)}
<div style={{ display: "flex" }}>
<div style={{ width: "75%" }}>
{posts.map((post, index) => (
<Post key={index} post={post} />
))}
</div>
<div style={{height: '100%', width: '25%'}}>
<div style={{ height: "100%", width: "25%" }}>
<Sidebar posts={posts} />
</div>
</div>
......
......@@ -36,49 +36,22 @@ export default class NewPost extends React.Component {
}
changeTitle(evt) {
// Updating the title input should call this
// value with the function argument `evt`, an event.
//
// If the text of the input is available at
// `evt.target.value`, how would you update
// `title` in state to that value?
this.setState({ title: evt.target.value })
}
changeBody(evt) {
// Updating the body input should call this
// value with the function argument `evt`, an event.
//
// If the text of the input is available at
// `evt.target.value`, how would you update
// `body` in state to that value?
this.setState({ body: evt.target.value })
}
render() {
/* This component has two state variables:
* - title
* - body
* Assign these to variables.
*
* Add the onSubmit prop to form, which should be set
* to this.addPost.
*
* Two additional props should be provided to the
* "Post Title" input:
* - value, which is set to the title value from state
* - onChange, which is set to this.changeTitle
*
* Two additional props should be provided to the
* "Post Body" textarea:
* - value, which is set to the body value from state
* - onChange, which is set to this.changeBody
*/
const { title, body } = this.state
return (
<form style={{padding: '2em'}}>
<form style={{padding: '2em'}} onSubmit={this.addPost}>
<div>
<input placeholder="Post Title" />
<input placeholder="Post Title" onChange={this.changeTitle} value={title} />
</div>
<div>
<textarea placeholder="Post Body" />
<textarea placeholder="Post Body" onChange={this.changeBody} value={body} />
</div>
<button type="submit">Add new post</button>
</form>
......
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import React, { PropTypes } from "react";
import ReactDOM from "react-dom";
class MyApp extends React.Component {
constructor() {
......@@ -13,80 +13,39 @@ class MyApp extends React.Component {
anObject: {
name: "Just an Object"
}
}
};
}
render() {
// The various elements in this.state should be "pulled" out
// here. For instance:
// var thing = this.state.thing;
//
// You can also use ES6 "destructuring" to make this process
// significantly faster: if the value exists on this.state,
// you can simply do:
// var { thing } = this.state;
//
// Finally, it's recommended that you use ES6's `const` keyword
// in place of `var`: `const` ensures that a value can't be changed
// (it's immutable), which is important to ensure that we don't
// mess up React's built-in state management.
// const { thing } = this.state;
const {
someText,
numberOne,
numberTwo,
someThings,
anObject: { name }
} = this.state;
return (
<div>
{/*
The render function for ComponentTwo
shows that it expects one prop:
`someText`.
*/}
<ComponentOne
/>
{/*
The render function for ComponentTwo
shows that it expects two props:
numberOne, and numberTwo.
*/}
<ComponentTwo
/>
{/*
The render function for ComponentThree
shows that it expects one prop:
an array `someThings`.
*/}
<ComponentThree
/>
{/*
Note in ComponentFour that it expects
a prop `name`, which can be found in `anObject`.
It _does not_ expect a prop `anObject`: instead,
you'll need to pass the value from _inside_ the
object.
*/}
<ComponentFour
/>
<ComponentOne someText={someText} />
<ComponentTwo numberOne={numberOne} numberTwo={numberTwo} />
<ComponentThree someThings={someThings} />
<ComponentFour name={name} />
</div>
)
);
}
}
class ComponentOne extends React.Component {
render() {
const { someText } = this.props;
return (
<span>{someText}</span>
)
return <span>{someText}</span>;
}
}
class ComponentTwo extends React.Component {
render() {
const { numberOne, numberTwo } = this.props;
return (
<span>{numberOne + numberTwo}</span>
)
return <span>{numberOne + numberTwo}</span>;
}
}
......@@ -95,22 +54,24 @@ class ComponentThree extends React.Component {
const { someThings } = this.props;
return (
<div>
{someThings.map(thing => <li key={thing}>{thing}</li>)}
{someThings.map(thing => (
<li key={thing}>{thing}</li>
))}
</div>
)
);
}
}
class ComponentFour extends React.Component {
render() {
const { name } = this.props;
return (
<span>{name}</span>
)
return <span>{name}</span>;
}
}
const root = document.getElementById("root");
if (root) { ReactDOM.render(<MyApp />, root); }
if (root) {
ReactDOM.render(<MyApp />, root);
}
export { MyApp, ComponentOne, ComponentTwo, ComponentThree, ComponentFour };
import React from 'react';
import React from "react";
import Header from './Header';
import Post from './Post';
import Sidebar from './Sidebar';
import Header from "./Header";
import Post from "./Post";
import Sidebar from "./Sidebar";
export default class Blog extends React.Component {
constructor() {
super();
// A state object should be initialized with
// the following:
// - blogTitle should be set to null
// - blogAuthor should be set to null
// - posts should be an empty array `[]`
this.state = {
blogTitle: null,
blogAuthor: null,
posts: []
};
}
componentDidMount() {
const url = 'https://bytesized-training-assets.herokuapp.com/blog.json';
const url = "https://bytesized-training-assets.herokuapp.com/blog.json";
fetch(url).then(resp =>
resp.json().then(json => {
this.setState({
blogTitle: json.blogTitle,
blogAuthor: json.blogAuthor,
posts: json.posts,
posts: json.posts
});
}),
})
);
}
render() {
// When you've replaced CHANGE_ME later in the render
// function, you can delete the below line.
var CHANGE_ME;
// The Blog component has three state values:
// - blogTitle
// - blogAuthor
// - posts
// Assign each of these to a variable of your choice.
// A number of additions need to be made to the return
// section of the render function below.
//
// Header:
// - Pass the value of your blogTitle variable as a
// prop `blogTitle`.
// - Pass the value of your blogAuthor variable as a
// prop `blogAuthor`.
// Post:
// - Update the value CHANGE_ME below to your posts
// variable. This will "loop" through the posts
// array and create a Post component for each post.
// Pass in each "item" as the prop post for each
// component.
// Sidebar:
// - Pass the value of your posts variable as a prop `posts`.
const { blogTitle, blogAuthor, posts } = this.state;
return (
<div>
<Header />
<div style={{display: 'flex'}}>
<div style={{width: '75%'}}>
{CHANGE_ME.map((item, index) => <Post key={index} />)}
<Header blogTitle={blogTitle} blogAuthor={blogAuthor} />
<div style={{ display: "flex" }}>
<div style={{ width: "75%" }}>
{posts.map((item, index) => (
<Post key={index} post={item} />
))}
</div>
<div style={{height: '100%', width: '25%'}}>
<Sidebar />
<div style={{ height: "100%", width: "25%" }}>
<Sidebar posts={posts} />
</div>
</div>
</div>
......
import React from 'react';
import React from "react";
export default class Comment extends React.Component {
render() {
// The Comment component receives a single prop.
// This prop has three fields on it:
// - commentAuthor
// - commentBody
// - postDate
// Try using ES6's "destructuring" syntax to quickly
// define all three as variables. For instance, given
// an object like:
//
// var obj = { name: "Me", age: 99 }
//
// I can use:
//
// var { name, age } = obj;
//
// To quickly set both variables.
//
// Do the same with `author`, `body`, and `date`, and replace
// the static text below with the values from these
// variables.
//
const {
comment: { commentAuthor, commentBody, postDate }
} = this.props;
return (
<div>
<h5>Author</h5>
<p>Body</p>
<h5>{commentAuthor}</h5>
<p>{commentBody}</p>
<p>
<small>Date</small>
<small>{postDate}</small>
</p>
</div>
);
......
import React from 'react';
import React from "react";
export default class Header extends React.Component {
render() {
// The Header component receives two props that
// you should have defined previously, in the Blog
// component. Set these props to variables, and replace
// "Title" and "Author" with those values in the
// return portion of this function.
const { blogTitle, blogAuthor } = this.props;
return (
<div style={{background: '#eee', padding: '1em 4em'}}>
<h1>Title</h1>
<h2>Author</h2>
<div style={{ background: "#eee", padding: "1em 4em" }}>
<h1>{blogTitle}</h1>
<h2>{blogAuthor}</h2>
</div>
);
}
......
import React from 'react';
import Comment from './Comment';
import React from "react";
import Comment from "./Comment";
export default class Post extends React.Component {
render() {
// The Post component receives one prop. That prop
// contains three pieces of data that we care about:
//
// - postTitle
// - postContent
// - comments
//
// Assign each of these to a variable of your choice.
// Remember that because they are _on_ the passed-in
// prop, you'll call them in a format like:
// var myProp = this.props.myProp;
// var myField = myProp.myField;
const {
post: { postTitle, postContent, comments }
} = this.props;
// Replace the h1 "Title" text with your postTitle.
// Replace the p "Content" text with your postContent.
// Replace the static CHANGE_ME in line 38 by mapping through your
// comments variable, rendering a <Comment> component
// with the prop comment. This will look somewhat like
// the following:
//
// {myArray.map((value, index) =>
// <Subcomponent key={index} prop={value} />
// )}
return (
<div style={{padding: '2em'}}>
<h1>Title</h1>
<p>Content</p>
{CHANGE_ME.map((comment, index) => <Comment key={index} />)}
<div style={{ padding: "2em" }}>
<h1>{postTitle}</h1>
<p>{postContent}</p>
{comments.map((comment, index) => (
<Comment key={index} comment={comment} />
))}
</div>
);
}
......
import React from 'react';
import React from "react";
export default class Sidebar extends React.Component {
render() {
// When you have replaced CHANGE_ME later in the
// render function, you can remove the below line.
var CHANGE_ME;
// The Sidebar component receives one prop that
// you should have defined previously, in the Blog
// component.
//
// Set this prop to a variable, and then "loop"
// through it using `map`. In the map function, return
// a <li> tag with the post title for each post. A
// post has the format:
//
// { postTitle: "Title", ... }
//
// To display the post title, you'll want to use
// post.postTitle in your map function.
//
// You may want to look at the map call in the Blog
// component's render function, to see a similar
// pattern.
//
const { posts } = this.props;
return (
<div style={{background: "#eee", padding: "1em"}}>
<div style={{ background: "#eee", padding: "1em" }}>
<h3>Recent posts</h3>
<ul>
{posts.map((post, index) => (
<li key={index}>{post.postTitle}</li>
))}
</ul>
</div>
)
);
}
}
import React from 'react';
import ReactDOM from 'react-dom';
var PROP_TEXT_HERE;
// No changes are needed above this line.
import React from "react";
import ReactDOM from "react-dom";
class MyApp extends React.Component {
render() {
// Instead of a span below, try using
// MyComponent, as well as passing a name prop.
return (
<div>
<span>Placeholder</span>
<MyComponent name="John Smith" />
</div>
);
}
......@@ -19,14 +13,10 @@ class MyApp extends React.Component {
class MyComponent extends React.Component {
render() {
// Replace PROP_TEXT_HERE with the
// `name` prop passed in to the component.
// Remember to define a name variable, using
// the value from `this.props`.
const { name } = this.props;
return (
<div>
<span>{PROP_TEXT_HERE}</span>
<span>{name}</span>
</div>
);
}
......@@ -34,9 +24,9 @@ class MyComponent extends React.Component {
// No changes are needed below this line.
const root = document.getElementById('root');
const root = document.getElementById("root");
if (root) {
ReactDOM.render(<MyApp />, root);
}
export {MyApp, MyComponent};
export { MyApp, MyComponent };
import React from 'react';
import ReactDOM from 'react-dom';
import React from "react";
import ReactDOM from "react-dom";
// Try importing the component Gravatar from 'react-gravatar'.
import Gravatar from "react-gravatar";
const MyContext = React.createContext();
class Application extends React.Component {
// Our Application should have state. You can either
// set state using the constructor, or more simply
// by using state = {} inside of the component
// definition.
//
// Try setting the state to an object with
// the keys and values:
// - Name, set to your name
// - Age, set to your age
// - Email, set to your email
// - City, set to the city you live in
state = {
name: "Octocat",
age: "40",
email: "octocat@github.com",
city: "San Francisco, CA"
};
// Next, update the Application component to
// render MyInfo inside of a div.
// Pass all the values from state to MyInfo as props.
// You can do this by using the spread operator:
// <SampleComponent {...this.state} />
render() {
return null;
return (
<div>
<MyContext.Provider value={{ state: this.state }}>
<Layout />
</MyContext.Provider>
</div>
);
}
}
const Layout = () => (
<div>
<header>
<h1>My application</h1>
</header>
<main>
<MyInfo />
</main>
</div>
);
class MyInfo extends React.Component {
// Inside the render function, return the following inside of a div:
// The Gravatar component, passing 'this.props.email' as the prop 'email'.
// An h1 with the value 'this.props.name'
// An h2 with the value '{this.props.age} in {this.props.city}'. There's
// a couple ways to format this, so it's left as an exercise for you to do.
render() {
return (
<MyContext.Consumer>
{context => (
<div>
<Gravatar email={context.state.email} />
<h1>{context.state.name}</h1>
<h2>
{context.state.age} in {context.state.city}
</h2>
</div>
)}
</MyContext.Consumer>
);
}
}
// Over time, applications can get more complex, and a simple
// two-component design may not be appropriate.
// For instance, let's add a Layout component below, which
// renders the following:
// A 'header' element, with the 'h1' text "My application"
// inside of it
// A 'main' element, which renders MyInfo.
//
// Go back up to Application, and replace MyInfo with Layout.
//
// Notice that you now have an issue with passing props:
// either you need to pass props down _through_ Layout, through
// two components, or you need some other solution.
//
// At scale, you can imagine this solution of passing props down
// stops being efficient, and becomes a source of confusion and errors.
// To solve this, we'll introduce React contexts to this application.
// To begin, we need to create a context, using React.createContext().
// Assign it to the variable MyContext.
// We also need to update Application to become a "Provider" component.
// In render, wrap Layout with the following:
// The component MyContext.Provider, passing the prop value. This prop
// is an object, with a key state set to this.state.
// Remember that Layout should still be inside the MyContext.Provider
// component.
// We've created our context and Provider information, now we need to use it.
// In MyInfo, wrap your presentation code in the component <MyContext.Consumer>,
// which has one _child_ JSX expression:
//
// <SampleComponent>
// {expression}
// </SampleComponent>
//
// This expression should be a function with one argument, context.
// Our context will be equivalent to the "value" prop we defined in our
// context provider. This means that the state that we've previously defined
// will be available as `context.state`.
//
// This is the data that we want to use to populate our MyInfo component.
// Replace each call to `this.state` as needed to use the context state.
//
// Once you've completed this, look through the code. Does it make sense where
// context is both defined, and used? Can you see how this pattern could be
// useful in the future?
const root = document.getElementById("root");
if (root) { ReactDOM.render(<Application />, root); }
if (root) {
ReactDOM.render(<Application />, root);
}
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "passing-basic-props",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-scripts": "1.0.11"
},
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-intro {
font-size: large;
}
@keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (!isLocalhost) {
// Is not local host. Just register service worker
registerValidSW(swUrl);
} else {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
}
});
}
}
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
......@@ -9,77 +9,42 @@ class NetworkedComponent extends React.Component {
constructor() {
super();
// Set this component's state:
// 1. `loading` should be `false`
// 2. `string` should be "n/a"
this.state = {
loading: false,
string: 'n/a'
}
}
componentDidMount() {
// When this component mounts, we should
// begin loading data.
// To begin, use this.setState to set `loading`
// to `true`.
// Remember that `this.setState` takes a JS object:
// this.setState({ key: 'value' })
this.setState({ loading: true })
// This does not need to be changed.
var url = 'https://bytesized-training-assets.herokuapp.com/exercise.json';
// `fetch` makes a HTTP request to the url, then...
fetch(url).then(resp => {
// With the response, we try and turn it into
// a JavaScript object from JSON, using .json(), then...
resp.json().then(json => {
// With the variable `json` that is provided as
// the result of `resp.json()`, update the component state,
// using this.setState below:
// - `loading` should be set to `false`
// - `string` should be set to the value of `json.string`:
// this is the value of the key `string` in the returned
// JSON.
this.setState({
loading: false,
string: json.string
})
});
});
}
render() {
// This does not need to be changed.
var loadingOrString;
// Get two values from state:
// - loading
// - string
// Set these values to a variable name of
// your choice below.
// When you've replaced both instances of UPDATE_ME
// in this render function, you can delete its
// definition below.
var UPDATE_ME;
const { loading, string } = this.state
// Replace UPDATE_ME with the variable you defined
// to store `this.state.loading`.
if (UPDATE_ME) {
// If we're still loading, we use
// this custom LoadingComponent.
// This does not need to be changed.
if (loading) {
loadingOrString = <LoadingComponent />;
} else {
// If we aren't loading, we should display
// the string value from state instead.
// This will contain the data requested
// from the network. Replace UPDATE_ME
// with the variable you defined to
// store this.state.string.
loadingOrString = <h3>{UPDATE_ME}</h3>;
loadingOrString = <h3>{string}</h3>;
}
// This does not need to be changed.
return <div>{loadingOrString}</div>;
}
}
// No changes are needed below this line.
class LoadingComponent extends React.Component {
render() {
return (
......
import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import React, { PropTypes } from "react";
import ReactDOM from "react-dom";
var PROP_TEXT_HERE;
......@@ -9,43 +9,14 @@ class MyApp extends React.Component {
render() {
return (
<div>
{/*
Provide the necessary props for MyComponent below. Note
that you can also define variables above the `return`
line and pass them in, if that makes it easier to read.
Components can be defined across multiple lines to be easier
to read, as seen below.
More complicated prop definitions, such as objects, are done with
double-brackets: the below example provides complicatedProp as
an object: `{ name: 'value' }`. The additional set of brackets
indicates that this is a JSX value.
<MyComponent complicatedProp={{ name: 'value' }} />
Defining a function as a prop can be simplified using ES6 (modern JS syntax).
A function has an argument and "function body". Below is a simple function
that takes an argument and prints it to the console. Following it is the
shorter ES6 syntax version:
// Old version
var logMe = function(thing) {
console.log(thing)
}
// ES6
var logMe = thing => console.log(thing)
Passing a function like this as a prop should be easy. Define a function
of your choice in the render function (above the return line) in MyApp,
and pass the variable name as `myFunc` into `MyComponent` below.
*/}
<MyComponent
helloText="Hello!"
me={{ firstName: "John", lastName: "Smith" }}
myFunc={() => alert("Hello!")}
textColor="red"
/>
</div>
)
);
}
}
......@@ -56,8 +27,12 @@ class MyComponent extends React.Component {
const myFuncHandler = myFunc ? myFunc.bind(this) : () => {};
return (
<div>
<h1 onClick={myFuncHandler} style={{color: textColor}}>{helloText}</h1>
<h2>This component was created by {firstName} {lastName}</h2>
<h1 onClick={myFuncHandler} style={{ color: textColor }}>
{helloText}
</h1>
<h2>
This component was created by {firstName} {lastName}
</h2>
</div>
);
}
......@@ -70,12 +45,14 @@ MyComponent.propTypes = {
}).isRequired,
helloText: PropTypes.string.isRequired,
myFunc: PropTypes.func,
textColor: PropTypes.string,
}
textColor: PropTypes.string
};
// No changes are needed below this line.
const root = document.getElementById("root");
if (root) { ReactDOM.render(<MyApp />, root); }
if (root) {
ReactDOM.render(<MyApp />, root);
}
export { MyApp, MyComponent };
......@@ -4,59 +4,7 @@ import Header from "./Header";
import Post from "./Post";
import Sidebar from "./Sidebar";
// Make sure to visit src/Provider.js at the beginning
// of this exercise!
//
// Once you've done that, we can come back and rewrite the
// Blog component as a stateless functional component, or
// SFC. SFCs are written as arrow functions, with a single
// argument: a props object. The function should return
// HTML, similar to the render function in a class-based
// component. For instance:
//
// const MyComponent = props => <h1>Hello!</h1>
//
// Remember that a props object is a great opportunity
// to use destructuring. For instance, given a props object
// with a key count:
//
// const MyComponent = ({ count }) =>
// <h1>Count is {count}!</h1>
//
// Given the data passed into the Blog component by its new
// parent Provider, use destructuring to replace any previous
// references to blogTitle, blogAuthor, and posts from state,
// inside of your SFC.
//
// Once you've done this, proceed to each component and update
// it to an SFC as well.
export default class Blog extends React.Component {
constructor() {
super();
this.setState({
blogTitle: null,
blogAuthor: null,
posts: []
});
}
componentDidMount() {
const url = "https://bytesized-training-assets.herokuapp.com/blog.json";
fetch(url).then(resp =>
resp.json().then(json => {
this.setState({
blogTitle: json.blogTitle,
blogAuthor: json.blogAuthor,
posts: json.posts
});
})
);
}
render() {
const { blogTitle, blogAuthor, posts } = this.state;
return (
const Blog = ({ blogTitle, blogAuthor, posts }) => (
<div>
<Header blogTitle={blogTitle} blogAuthor={blogAuthor} />
<div style={{ display: "flex" }}>
......@@ -70,6 +18,6 @@ export default class Blog extends React.Component {
</div>
</div>
</div>
);
}
}
);
export default Blog;
import React from "react";
// This component should be rewritten as an SFC, or
// stateless functional component. Note the
// props being passed in currently, and rewrite
// the component to have these provided as part of
// the "props" function argument for your new SFC.
// If you're stuck, re-read the comments in src/Blog.js!
export default class Comment extends React.Component {
render() {
const {
comment: { commentAuthor, commentBody, postDate }
} = this.props;
return (
const Comment = ({ comment: { commentAuthor, commentBody, postDate } }) => (
<div>
<h5>{commentAuthor}</h5>
<p>{commentBody}</p>
......@@ -20,6 +8,6 @@ export default class Comment extends React.Component {
<small>{postDate}</small>
</p>
</div>
);
}
}
);
export default Comment;
import React from "react";
// This component should be rewritten as an SFC, or
// stateless functional component. Note the
// props being passed in currently, and rewrite
// the component to have these provided as part of
// the "props" function argument for your new SFC.
// If you're stuck, re-read the comments in src/Blog.js!
export default class Header extends React.Component {
render() {
const { blogTitle, blogAuthor } = this.props;
return (
const Header = ({ blogTitle, blogAuthor }) => (
<div style={{ background: "#eee", padding: "1em 4em" }}>
<h1>{blogTitle}</h1>
<h2>{blogAuthor}</h2>
</div>
);
}
}
);
export default Header;
import React from "react";
import Comment from "./Comment";
// This component should be rewritten as an SFC, or
// stateless functional component. Note the
// props being passed in currently, and rewrite
// the component to have these provided as part of
// the "props" function argument for your new SFC.
// If you're stuck, re-read the comments in src/Blog.js!
export default class Post extends React.Component {
render() {
const {
post: { postTitle, postContent, comments }
} = this.props;