MODULE 5 - 6 & 7 [ REACT JS NOTES ] BASICS FOR ALL WEB DEVELOPMENT
Step 1 - Install a React Router
A simple way to install the react-router is to run the following code snippet in the command prompt window.
C:\Users\username\Desktop\reactApp>npm install react-router-dom
Step 2 - Create Components
In this step, we will create four components. The App component will be used as a tab menu. The other three components (Home), (About) and (Contact) are rendered once the route has changed.
main.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router'
class App extends React.Component {
render() {
return (
<div>
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
{this.props.children}
</div>
)
}
}
export default App;
class Home extends React.Component {
render() {
return (
<div>
<h1>Home...</h1>
</div>
)
}
}
export default Home;
class About extends React.Component {
render() {
return (
<div>
<h1>About...</h1>
</div>
)
}
}
export default About;
class Contact extends React.Component {
render() {
return (
<div>
<h1>Contact...</h1>
</div>
)
}
}
export default Contact;
Step 3 - Add a Router
Now, we will add routes to the app. Instead of rendering App element like in the previous example, this time the Router will be rendered. We will also set components for each route.
main.js
ReactDOM.render((
<Router history = {browserHistory}>
<Route path = "/" component = {App}>
<IndexRoute component = {Home} />
<Route path = "home" component = {Home} />
<Route path = "about" component = {About} />
<Route path = "contact" component = {Contact} />
</Route>
</Router>
), document.getElementById('app'))
<Link>
Provides declarative, accessible navigation around your application.
<Link to="/about">About</Link>
to: string
A string representation of the Link location, created by concatenating the location’s pathname, search, and hash properties.
<Link to="/courses?sort=name" />
to: object
An object that can have any of the following properties:
pathname: A string representing the path to link to.
search: A string representation of query parameters.
hash: A hash to put in the URL, e.g. #a-hash.
state: State to persist to the location.
<Link
to={{
pathname: "/courses",
search: "?sort=name",
hash: "#the-hash",
state: { fromDashboard: true }
}}
/>
to: function
A function to which current location is passed as an argument and which should return location representation as a string or as an object
<Link to={location => ({ ...location, pathname: "/courses" })} />
<Link to={location => `${location.pathname}?sort=name`} />
<NavLink>
A special version of the <Link> that will add styling attributes to the rendered element when it matches the current URL.
<NavLink to="/about">About</NavLink>
activeClassName: string
The class to give the element when it is active. The default given class is active. This will be joined with the className prop.
<NavLink to="/faq" activeClassName="selected">
FAQs
</NavLink>
activeStyle: object
The styles to apply to the element when it is active.
<NavLink
to="/faq"
activeStyle={{
fontWeight: "bold",
color: "red"
}}
>
FAQs
</NavLink>
exact: bool
When true, the active class/style will only be applied if the location is matched exactly.
<NavLink exact to="/profile">
Profile
</NavLink>
strict: bool
When true, the trailing slash on a location’s pathname will be taken into consideration when determining if the location matches the current URL. See the <Route strict> documentation for more information.
<NavLink strict to="/events/">
Events
</NavLink>
<Switch>
Renders the first child <Route> or <Redirect> that matches the location.
How is this different than just using a bunch of <Route>s?
<Switch> is unique in that it renders a route exclusively. In contrast, every <Route> that matches the location renders inclusively. Consider these routes:
import { Route } from "react-router";
let routes = (
<div>
<Route path="/about">
<About />
</Route>
<Route path="/:user">
<User />
</Route>
<Route>
<NoMatch />
</Route>
</div>
);
If the URL is /about, then <About>, <User>, and <NoMatch> will all render because they all match the path. This is by design, allowing us to compose <Route>s into our apps in many ways, like sidebars and breadcrumbs, bootstrap tabs, etc.
Occasionally, however, we want to pick only one <Route> to render. If we’re at /about we don’t want to also match /:user (or show our “404” page). Here’s how to do it with Switch:
import { Route, Switch } from "react-router";
let routes = (
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/:user">
<User />
</Route>
<Route>
<NoMatch />
</Route>
</Switch>
);
Now, if we’re at /about, <Switch> will start looking for a matching <Route>. <Route path="/about"/> will match and <Switch> will stop looking for matches and render <About>. Similarly, if we’re at /michael then <User> will render.
React Redux:
Redux is a predictable state container for JavaScript apps based on the Flux design pattern. Redux can be used together with React, or with any other view library. It is tiny (about 2kB) and has no dependencies.
Redux follows three fundamental principles:
Single source of truth:
The state of your whole application is stored in an object tree within a single store. The single state tree makes it easier to keep track of changes over time and debug or inspect the application.
State is read-only:
The only way to change the state is to emit an action, an object describing what happened. This ensures that neither the views nor the network callbacks will ever write directly to the state.
Changes are made with pure functions:
To specify how the state tree is transformed by actions, you write reducers. Reducers are just pure functions that take the previous state and an action as parameters, and return the next state.
React Hooks:
Hooks is a new feature that lets you use state and other React features without writing a class.
This hook returns a stateful value and a function to update it. Originally, we had to initialise the apps state separately and then use the setState function to update the state’s value.
useState:
const [state, setState] = useState(initialState);
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
setState(newState);
During subsequent re-renders, the first value returned by useState will always be the most recent state after applying updates.
Let's see an example of useState hook example:
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App() {
const [count, setCount] = useState(0);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>You clicked {count} times!</h2>
<button onClick={() => setCount(count - 1)}>Decrement</button>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This hook takes a function that contains code (fetching data or subscribing to a service) and returns a function that will be executed every time before the effect runs and when the component is unmounted — in order to re-initialize itself from the last iteration.
useEffect:
useEffect(didUpdate);
Let's see an example of useEffect hook example:
import React, {useEffect,useState} from "react";
import ReactDOM from "react-dom";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Counter />, rootElement);
This hook accepts a context object and returns the current context value, as given by the nearest context provider for the given context.
Ex:
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css'
import './index.css';
const NameContext = React.createContext();
const App = () => {
return (
<NameContext.Provider value={"Rajat"}>
<div className="App">
<NameContext.Consumer>
{value => <h1>Hello! My Name is {value}!</h1>
</NameContext.Consumer>
</div>
</NameContext.Provider>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
Here, we are using the createContext() function to create a new instance of the context named NameContext. This instance is connect to values: Provider and Consumer.
The NameContext.Provider component is used to initialise the data. Then we have to wrap our content in a NameContext.Consumer and use the render props pattern of passing a function as a child in order to retrieve the value and display it.
import React, {useContext} from 'react';
Then, replace the NameContext.Consumer component and the whole h1 tag inside it with a simple Greet component, as shown below:
const App = () => {
return (
<NameContext.Provider value={"Rajat"}>
<div className="App">
<Greet/>
</div>
</NameContext.Provider>
)
}
We haven’t written this Greet component yet, so let’s take care of that right below the App component as shown below:
const Greet = () => {
const value = useContext(NameContext);
return <h1>Hello! My Name is {value}</h1>;
}
And That’s All! We simply call the useContext hook on the value, pass in the NameContext object to it and we can then use the value anywhere inside that component.
Higher order components are JavaScript functions used for adding additional functionalities to the existing component. These functions are pure, which means they are receiving data and returning values according to that data. If the data changes, higher order functions are re-run with different data input. If we want to update our returning component, we don't have to change the HOC. All we need to do is change the data that our function is using.
Higher Order Component (HOC) is wrapping around "normal" component and provide additional data input. It is actually a function that takes one component and returns another component that wraps the original one.
Let us take a look at a simple example to easily understand how this concept works. The MyHOC is a higher order function that is used only to pass data to MyComponent. This function takes MyComponent, enhances it with newData and returns the enhanced component that will be rendered on the screen.
import React from 'react';
var newData = {
data: 'Data from HOC...',
}
var MyHOC = ComposedComponent => class extends React.Component {
componentDidMount() {
this.setState({
data: newData.data
});
}
render() {
return <ComposedComponent {...this.props} {...this.state} />;
}
};
class MyComponent extends React.Component {
render() {
return (
<div>
<h1>{this.props.data}</h1>
</div>
)
}
}
export default MyHOC(MyComponent);
Axios is promise-based and thus we can take advantage of async and await for more readable asynchronous code. We can also intercept and cancel requests, and there’s built-in client side protection against cross site request forgery.
We can start by adding Axios to our project:
$ npm install axios --save
GET Requests
If we then create a new component named PersonList, we’d be able to hook into the componentDidMount lifecycle hook and perform a GET request after importing axios.
import React from 'react';
import axios from 'axios';
export default class PersonList extends React.Component {
state = {
persons: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const persons = res.data;
this.setState({ persons });
})
}
render() {
return (
<ul>
{ this.state.persons.map(person => <li>{person.name}</li>)}
</ul>
)
}
}
Copy
Using axios.get(url) we then get a promise which returns a response object. As we’re looking for the response data, we’ve assigned the value of the person to res.data.
We can also get other information about our request such as the status code under res.status or more information inside of res.request.
POST Requests
We can handle other verbs such as POST and PUT in a similar fashion. Let’s create a form that allows for user input and subsequently POST the content to an API:
import React from 'react';
import axios from 'axios';
export default class PersonList extends React.Component {
state = {
name: '',
}
handleChange = event => {
this.setState({ name: event.target.value });
}
handleSubmit = event => {
event.preventDefault();
const user = {
name: this.state.name
};
axios.post(`https://jsonplaceholder.typicode.com/users`, { user })
.then(res => {
console.log(res);
console.log(res.data);
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Person Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<button type="submit">Add</button>
</form>
</div>
)
}
}
Copy
Using POST gives us that same response object with information that we can use inside of our call.
DELETE Requests
We can delete items from our API using axios.delete and passing the URL as a parameter. Let’s change our form to delete a user instead of adding a new one:
import React from 'react';
import axios from 'axios';
export default class PersonList extends React.Component {
state = {
id: '',
}
handleChange = event => {
this.setState({ id: event.target.value });
}
handleSubmit = event => {
event.preventDefault();
axios.delete(`https://jsonplaceholder.typicode.com/users/${this.state.id}`)
.then(res => {
console.log(res);
console.log(res.data);
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Person ID:
<input type="text" name="id" onChange={this.handleChange} />
</label>
<button type="submit">Delete</button>
</form>
</div>
)
}
}
Simple POST request with a JSON body using fetch
This sends an HTTP POST request to the JSONPlaceholder api which is a fake online REST api that includes a /posts route that responds to POST requests with the contents of the post body and an id property. The id from the response is assigned to the react component state property postId so it can be displayed in the component render() method.
componentDidMount() {
// Simple POST request with a JSON body using fetch
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React POST Request Example' })
};
fetch('https://jsonplaceholder.typicode.com/posts', requestOptions)
.then(response => response.json())
.then(data => this.setState({ postId: data.id }));
}
Comments
Post a Comment