After playing around with with a RESTful Express application using pure JS, I decided in 2018 it was time to learn a different way of doing things. Enter React
which you might have heard about.
I have been learning from various sources the main ones are:
Stephen Grider's Modern React with Redux and
Wesbos' course React for Beginners
Stephen I think is great at introducing concepts and explaining them. Wes takes you through the end-to-end process in a 'real life' way with some helpful tips along the way.
This first post is just a summary of some of the key parts of React, and explore some newbie errors before we go into using them in anger.
By the way,make sure you have a good grasp of ES6 before getting into React for two reasons:
- The syntax will make more sense
- Things you may think of as part of React are really just leveraging whats already in ES6.
The Building Blocks of React
Before we get into building something cool, we need to understand some core concepts of React:
- Setting up React
- JSX
- Rendering
- React Application Structure
- Imports and Exporting Components
- Components
- State
How do we set up React?
In short, you don't.
In slightly longer, setting up React can be complicated. Create-React-App is one tool that makes it easier to develop a React app. We can eject from when we are production ready but that's a topic for later on.
Both Stephen Grider and Wes Bos recommend a pre-configured environment to get familar with React first so that's what I did.
JSX : What is it and how can it show stuff on the page?
JSX is a way introduced in React of writing easily legible HTML in a otherwise JS file. It isn't technically required but writing in pure JS gets messy fast. One drawback is that JSX doesnt run on a browser by default so we need to make use of Transpiling tools, namely Babel
and Webpack
, to turn it into JS the browser can understand.
The index.js file references a script called bundle.js
file will parse your jsx code and bundle it all into one big file with all the magic to make it run.
If you view the source of bundle.js you will appreciate that it's sensible to rely on Create-React-App while you are getting the hang of React itself.
You can make a JSX file as you would any other file in your IDE. But there is a few things to be aware of...
The JSX rendering minefield
Let's take the following JSX example:
const App = () => {
return <div> Hi </div>;
}
React.render(App)
Will it work? No.
Error 1: React is not defined
If we simply do React.render(App)
. It wont know what React is as the JSX has no reference to it.
To solve this, we ensure we need to explicitly reference React via a module. To do this, at the top we need to add:
`import React from 'react'
In plain english, this means go grab the react package as an object called React. So lets try it again..
Error (well ... warning) 2: React.Render is deprecated. Please use ReactDOM.render from ('react-dom") instead
React used to be one package, however now it is split into several parts because as React has become more popular, all it's features may not apply.
For this we need ReactDOM which is focused on iteracting with the DOM. We need to import that to get rid of the warning:
import ReactDOM from 'react-dom'
and change the render statement to use ReactDOM:
ReactDOM.render(App)
Alright it should work now right?
Error 3: Uncaught error: Invariant Violation: ReacDOM.render(): Invalid Component Element. Instead of passing a component class, make sure to instantiate it by passing it to React.createElement
Yep, still not working…
The 'App' function we used is actually a defined class of component
, it cant be added to the DOM, it is effectively a blueprint to create an instance.
We can make an instance by using tags: <App></App>
. This can be self closed by doing <App />
instead which gives us this:
ReactDOM.render(<App />)
So maybe one way of looking at JSX is that we can make our own HTML tags that can store data and pass it to each other. Anyhow, it has to work now right?!
Error 4: Target container is not a DOM element
Ok, so this is quite straightforward. The render method needs a RENDER TARGET, a place in the DOM to put the React application. To do this, there is a second argument we need to add. For this example, we will say there is a div in our HTML with the class "container".
js
ReactDOM.render(<App /> , document.querySelector(".container");
And now….. it will work! So there better be a good reason for going through all that effort right?....right?
React Application Structure
A good react app is split into self-contained, non-code repeating snippets called Containers.
There is a little bit of Art to determine how to split things into components but one key rule is One Component per file This allows a clear speration of concerns, a team of developers can focus on a particular component in a relatively safe way.
An example a video player app might consist of components for:
• Search,
• The Video player
• Video Details
• An unordered list of other videos
• Items within that list.
You will want a container component to keep them all within which is traditionally defined as index.js
. The rest can typically kept in a components folder.
Here is an example file structure of what I mean:
-src
- index.js
- Components
- search_bar.js
- video_detail.js
- video_list_item.js
But like I say, it’s a little bit of an art that depends on what you are doing, just aim for clarity and consistancy whatever you do.
Importing and Exporting Components
Once you have your JS files containing a component, how do you use them? First make sure your component file has the following:
- Import React (and other dependancies)
- Write your component in a function
- Export the function using the following line:
export default <component>
In your Index.js, import the component as you would with any other package:
import <component> from <file reference><js file>
Don't forget the file reference, in the video player example above the import file will look like:
js
import videoPlayer from './components/video_detail'
Now we can add the component in Index using JSX tags: <videoPlayer />
The two types of Components
If we step back, we have thus far created components that are functions like:
const App = () => {
return <div> Hi </div>;
}
This is a functional component. It is a component that just spews out JSX. When more internal logic and decision making is required, e.g event handling, we use class-based components. This uses Es6 classes like so:
class Search extends React.Component { }
When we use classes we still need it to output JSX, we do this via adding a Render Method:
class Search extends React.Component {
render() { //render method
return <input />;
}
}
Put simply, use functional components for simple stuff that renders out, class-based components for extra smarts.
A simple way of handling an event in a Class-based component
There is two steps to do this:
Declare an event handler - something that is ran when the event happens
Pass the event handler to the element we want to monitor the event.
Something like this:
class Search extends React.Component {
render() { //render method
return <input onChange={this.onInputChange} />;
}
onInputChange(event){
console.log(event.target.value); //whatever is typed is logged
}
}
The react docs explains more about different events.
This is where State comes in
State is one of the hardest things to understand about React
State is a plain Javascript object that is used to record and react to events. Every class-based component has a state object and a change to state causes the component to rerender plus any children.
To use state we first we need to initialise:
class Search extends React.Component {
constructor(props) {
super(props);
this.state = {searchTerm: ' ' };
}
Second, we can change the state by using the setState method:
onInputChange(event){
this.setState({ searchTerm: event.target.value })
}
}
Always use the setState method, do not manually update the state object, else react wont know about the change.
Why do we do this?
Since state updates when it sees a change, the properties of the state object are good to use in the render method:
render() {
return <div>
<input onChange={this.onInputChange} />;
Value of the input: {this.state.searchTerm}
</div>
};
This will result in a display that automatically updates as the user makes changes
This is cool! However this is not the right way around. The Input controls the state. However the input should be updated by the state, so how do we do that?
Proper Controlled Components
In this technique, the state controls the value of element. It is best shown first…
<input value={this.state.searchTerm} onChange={event => this.setState({ term: event.target.value}) />
The sequence of events is now different:
when the component is rendered for the first time the state tells the input what its value is, which is probably blank.
When the user triggers the event, the event causes setState to update the searchTerm in state.
The change of state causes the component to rerender which then changes the value to whatever it is in State.
It's the Circle of State, you can add your own Lion King GIF here.
Conclusion
So that's the first key concepts of React, we will talk about them some more and encounter new ones as we go into using them in anger.
Top comments (0)