Recently I've been learning react, I'm by no means an expert but I enjoy teaching as I learn. It's a great way to help people learn, cement what I've learnt and also get some feedback on what I may not have understood. As I'm still a learner I'll be converting an old project of mine over to react, the project I've chosen is material design switches.
The aim is to be able to just write a single HTML tag and get a simple, nice and accessible toggle switch back. I'll be using JSFiddle to show the various steps.
<MaterialSwitch>Toggle switch</MaterialSwitch>
Setup
First things first, let's make a quick hello world!
. I know we can use a react functional component rather than a full class while we're at this simple stage but we'll be needing to use a class later, to get access to states, so let's start with one.
The class needs to extend React.Component
and just needs the render()
function. Here it is.
ReactDOM.render(<MaterialSwitch />, document.querySelector("body"))
You'll notice I have this line at the end for this demo we can pretend it's the same as having <MaterialSwitch />
in the html.
Create
Now let's actually think about the component we want to create, it's a checkbox so we need;
- Label text
child
- text to appear next to checkbox - readOnly
property
- is the checkbox readOnly? - disabled
property
- is the checkbox disabled? - defaultChecked
property
- checked state on load - checked
state
- internal checked state
I think that's all we will need, I've got 3 different labels child
, property
and state
. Both children and properties are passed in from a higher level and the component does not have any control over them, they simply exist. States however can be changed from within a component and are the beauty of React.
Adding State and Props
Because we want to use states we're going to need to use the constructor function. When you use the construction function you need to be sure to pass props
to the super
function in order to keep things working right.
constructor(props) {
/**
* This is the super function it ensures
* the constructor function still carries
* out it's original purpose.
*/
super(props);
/*
* Here I am setting up the default states
* I am setting "checked" to be equal to
* the property "defaultChecked"
*/
this.state = {
checked: props.defaultChecked
}
}
We're also going to want to copy in our HTML from the existing project but with a few React changes.
render() {
// This is how get our props, we could have
// done this.props.readonly for each place
// we wanted to use the props but I think
// this is easier to understand
const {children, readonly, disabled, defaultChecked } = this.props;
return (
<label className="md_switch">
<input
readonly={readonly}
disabled={disabled}
defaultChecked={defaultChecked}
type="checkbox"
/>
<span className="md_switch__toggle"></span>
{children}
</label>
)
}
Anywhere you want to use a variable in the HTML
, well JSX techically, just place the variable name inside some braces like so {variable}
.
It's also worth pointing out, anywhere where you might want to add a class
to your element you'll have to use className
rather than the standard class
this is because class
is a reserved word in javascript.
Adding functions
All we need from our function is for it to update the state when the checked attribute of the checkbox changes. The function will be easy enough to write but there are another couple of things we'll need to do to get it all working.
/**
* Update checked on change
*
* @param {Event} event - from the changed element
*/
changeHandler(event) {
this.setState({checked: event.target.checked})
}
Simple enough, set the checked state to the target of the event's checked param. Now let's link it up to the HTML
/JSX
.
render() {
const {children, readonly, disabled, defaultChecked } = this.props;
return (
<label class="md_switch">
<input
readonly={readonly}
disabled={disabled}
defaultChecked={defaultChecked}
onChange={this.changeHandler}
type="checkbox"
/>
<span class="md_switch__toggle"></span>
{children}
</label>
)
}
To add a function to the event you just need to add the onEvent tag, we want to trigger on change so we'll use onChange
(notice the camelCase).
This still won't work though as within this.changeHandler
the context of this
has been changed to the event
. To ensure the context of this
remains bound to our react component we need to add the following line to our constructor function.
this.changeHandler = this.changeHandler.bind(this);
Events
For the last bit of JS we're going to want to allow users of our component to use events, so we'll pass our events back up using props
. As we're already using the onChange
event we'll need to modify our function to sent the event up further.
/**
* Update checked on change
*
* @param {string} text
*/
changeHandler(event) {
const { onChange } = this.props;
this.setState({checked: event.target.checked});
If(typeof onChange === "function") onChange(event);
}
I get onChange
from props and now we can pass the event up. I've added the typeof
function just in case the user adds something strange or even nothing at all.
The HTML
/JSX
bit is a lot easier we just need to pass our prop on like so
render() {
const {children, readonly, disabled, defaultChecked, onInput } = this.props;
return (
<label class="md_switch">
<input
readonly={readonly}
disabled={disabled}
defaultChecked={defaultChecked}
onChange={this.changeHandler}
onInput={onInput}
type="checkbox"
/>
<span class="md_switch__toggle"></span>
{children}
</label>
)
}
Styling
Styling is as simple as adding our CSS I won't go over the CSS as it's exactly the same as the original post I was recreating. So here it is.
Wrapping up
Well there we have it, we have made our first react component. We have a simple tag that can used to input a material toggle.
Let's look at the HTML
and the final result.
<div>
<MaterialSwitch>Toggle Switch</MaterialSwitch>
<br />
<MaterialSwitch defaultChecked>Pre-activated</MaterialSwitch>
<br />
<MaterialSwitch disabled>Disabled</MaterialSwitch>
<br />
<MaterialSwitch defaultChecked disabled>
Activated and disabled
</MaterialSwitch>
<br />
<MaterialSwitch>
Really really really long label
content to hopefully span several lines
to show that the checkbox will stay central.
</MaterialSwitch>
</div>
And that's it, we're home free, thanks for reading. If you have any questions, suggestions or just wanna chat feel free to comment down below. Thanks again!
🦄🧠💕🦄🦄💕❤🧠💕❤