Turning your reusable react component into an npm package

By design, it’s best practice to have react components made in a reusable format. Have you ever thought of turning that reusable component into a package that you could use in future without necessarily recreating it? In this article I share from my own experience turning a react component for displaying american style phone numbers into a reusable npm package.

The component

My component is a simple react component: but I need to import world country codes and american area codes in order to provide these as select options for users. So, in my component I use a JSON object of the type for country codes:

const countryCodes = [{
“country”: “Afghanistan”,
“code”: “93”,
“acronym”: “AF / AFG”
}, {
“country”: “Albania”,
“code”: “355”,
“acronym”: “AL / ALB”
}, {
“country”: “Algeria”,
“code”: “213”,
“acronym”: “DZ / DZA”
},...
}];

I also use american area codes in JSON format like this:

const areaCodes = [{
“area”: “Alaska”,
“code”: “907”
}, {
“area”: “Alabama”,
“code”: “205, 251, 256, 334”
}, {
“area”: “Arkansas”,
“code”: “479, 501, 870”
}...
}];

I have written these in ES6 because who writes in ES5 any more, right? I arrange the JSON files, which I could also import individually just above this react component:

const phoneToString = phone => `+${phone.countryCode} (${phone.areaCode}) ${phone.midNumber}-${phone.endNumber}`;const stringToPhone = (phoneString) => {
const ps = phoneString.split(/[^\w\s]/gi);
for (let i = 0, n = ps.length; i < n; i += 1) {
if (ps[i] === ‘’) {
ps.splice(i, 1);
}
}
return ps;
};
const inputStyles = {
border: ‘1px solid #000’,
borderRadius: ‘3px’,
width: ‘102px’,
height: ‘28px’,
display: ‘inline-block’,
};
const selectInputStyle = {
background: ‘none’,
border: ‘none’,
width: ‘100px’,
height: ‘25px’,
};
export default class TelephonePicker extends Component {
constructor(props) {
super(props);
this.state = {
countryCodes,
areaCodes,
telephone: {
countryCode: stringToPhone(this.props.phone)[0].trim(),
areaCode: stringToPhone(this.props.phone)[1].trim(),
midNumber: stringToPhone(this.props.phone)[2].trim(),
endNumber: stringToPhone(this.props.phone)[3].trim(),
},
};
this.handleChange = this.handleChange.bind(this);
this.renderCountryCodes = this.renderCountryCodes.bind(this);
this.renderAreaCodes = this.renderAreaCodes.bind(this);
}
handleChange(e) {
const { name, value } = e.target;
this.setState({ telephone: Object.assign(
{},
this.state.telephone, { [name]: value }) },
() => this.props.writePhone(phoneToString(this.state.telephone)));
}
renderCountryCodes() {
return this.state.countryCodes.map(countryObj => (
<option
key={countryObj.country}
value={String(countryObj.code)}
>
+{countryObj.code} ({countryObj.acronym.split(‘ / ‘)[1]})
</option>
));
}
renderAreaCodes() {
return this.state.areaCodes.map((areaObj, j) =>
areaObj.code.split(‘, ‘).map((code, i) => (
<option
key={String(j) + String(i)}
value={String(code)}
>
{code}
</option>
)
));
}
render() {
return (
<div className=”container”>
<div style={inputStyles}>
<select
name=”countryCode”
style={selectInputStyle}
defaultValue={String(this.state.telephone.countryCode)}
onChange={this.handleChange}
>
{this.renderCountryCodes()}
</select>
</div>
{‘ ( ‘}
<div style={inputStyles}>
<select
name=”areaCode”
style={selectInputStyle}
defaultValue={String(this.state.telephone.areaCode)}
onChange={this.handleChange}
>
{this.renderAreaCodes()}
</select>
</div>
{‘ ) ‘}
<div style={inputStyles}>
<input
type=”text”
name=”midNumber”
value={this.state.telephone.midNumber || ‘’}
onChange={this.handleChange}
style={{ width: ‘100px’ }}
/>
</div>
{‘ — ‘}
<div style={inputStyles}>
<input
type=”text”
name=”endNumber”
value={this.state.telephone.endNumber || ‘’}
onChange={this.handleChange}
style={{ width: ‘100px’ }}
/>
</div>
</div>
);
}
}
TelephonePicker.propTypes = {
phone: PropTypes.string.isRequired,
writePhone: PropTypes.func.isRequired,
};

With this component working as part of a real react project, the next step is to structure your project with the relevant files only, to babelify and package it in a minified production-ready format.

Project Structure

This is where you adopt the structure that your package should take to when it is published. In my case, I have all my files at the root of the /dist/ directory. In here, I include my react component in a file and name it main.js. This file is added to .gitignore since I do not want it to be part of the published package.

At the root I will also do npm init as every npm package must have package.json generated from this command. While initializing this, make sure to put your main file as the end result minified version of your component which in my case is index.min.js. It is also a great idea to have the “author” and “repository” parts correctly filled out.

Babelify

I used the babel cli package, installed globally through terminal to transpile my ES6 code into ES5. Install babel-cli globally by running npm install -g babel-cli on your terminal. This allows you to use babel as a command on your terminal and you can transpile your main.js file into index.js using the command babel main.js --out-file index.js --presets=es2015,react. This will create index.js at the root of your project. This then needs to be minified in order to be ready for production.

Minify

To minify the resultant index.js file, you can use a cli package for minification installed globally. I used the minifier package which only works with transpiled javascript code. Install it globally by running npm install [-g] minifier. While at the root of the project to be published, run minify --output index.min.js index.js. We want the minifyed version to have the .min.js extension.

Publish

Lastly, publish your package. To do this, one needs to have an account registered in the npm registry. If you don’t have one, you can easily add one by running npm adduser, but if you do, simply login to your account by running npm login. This stores your credentials on the client. Once logged in, then run npm publish. This publishes everything that is not listed in the .gitignore file. For more information on publishing your package please see the npm docs here.

I hope this is helpful. If you have any questions on this, feel free to tweet me @natemmartin. You can also check out my library on GitHub https://github.com/n8e/react-american-phone-numbers

Feel free to install it and use it in your projects :-)

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

OnCollisionEnter Vs. OnTriggerEnter — When to use them?

How to Receive Webhook Events With Netlify Functions and JavaScript

Angular Continued…..

So I still can’t run my Node.js 8 code on AWS Lambda, or can I?

Solving Maximum Product Of Two Elements In An Array

Visualizing Sorting Algorithms with Web Audio for the Heck of It

Working with Material UI

A Beginners Journey Visualising The World Cup, Utilising Mapbox

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
n8e

n8e

More from Medium

Using the State Hook in React: useState() Hook

Evolution of identifying duplicates in array

Modular Architecture: A Framework For Building Clean, Easy-To-Maintain JavaScript Apps

React Components