中国福利彩票开奖结果:File API Input Layer

December 31st, 2016. Tagged: JavaScript, react, tools

Every once in a while I feel inspired to create a little tool to "do one thing" (tm). But often I get distracted and a little too lazy to get off the ground and forget all about it. So I thought maybe a little helper can, well, help move things along.

Enter FAIL, short for File API Input Layer (yup, totally made up to match the acronym).

FAIL

It's a very, very simple blueprint for any single-page tool that needs to read a file (or files) from the user and do something with this file. All client-side, naturally, what cannot be done in JavaScript these days?

Here's the thing in action - it takes images through drag and drop or though a file input dialog. Then simply shows the images with some data about them:

screen-shot-2016-12-29-at-7-11-06-pm

FAIL doesn't do anything with the images, it's the job of the future tools that could be using it.

DEMO

React

FAIL is written in React. I'm probably still a little old-school and when I have an idea I create a blank test.html and go from there, vanilla-like. But in this case I decided to go against my lazy-bum instinct and use something that can get me off the ground. And allow me to write all the ES2019 I want. Even though this means dreaded SETUP. I hate setting stuff up, kills the mood ?? But in this case turns out React is just perfect for this type of tool.

I couldn't be bothered with Redux or whatever though, not even my self-grown DIY flux implementation. That would be too much.

I used create-react-app to get started:

$ create-react-app fail
$ cd fail
$ npm start

Code

I shoved all the JS in one file (can't be bothered) and it still ended up under 100 lines of code. The app's components are composed like:

<App>
  <Uploads />
  <Results />
</App>

App is actually the one generated by create-react-app. In its render() I put:

render() {
  return (
    <div className="App">
      <div className="App-header">
        <h1>Upload me some images</h1>
        <p>pst, you can just drop them anywhere</p>
      </div>
      <div className="Tool-in">
        <Uploads onChange={this.handleUploads.bind(this)} />
      </div>
      <div className="Tool-out">
        <Results files={this.state.files} />
      </div>
    </div>
  );
}

Simple, eh?

Now Uploads and Results are even simpler. They just render something. They don't need to maintain state. So they can be implemented as stateless functional components. If you're not familiar with those see this diff where I switched from ES class syntax to functional components.

Uploads is just a file input:

const Uploads = ({onChange}) =>
  <div>
    <label htmlFor="files" className="Uploads-select">Select files...</label>
    <input 
      type="file" 
      id="files" 
      multiple 
      accept="image/*" 
      style={{display: 'none'}} 
      onChange={onChange}
    />
  </div>;

Results just loops though the uploaded files to put up a table:

const Results = ({files}) => {
  if (files.length === 0) {return <span/>;}
  return (
    <table className="Results-table">
      <tbody>
      <tr><th>Image</th><th>filename</th><th>size</th><th>mime</th></tr>
      {files.map((f, idx) => {
        if (!f.type.startsWith('image/')) {
          return null;
        }
        return (
          <tr key={idx}>
            <td><img alt={f.name} src={window.URL.createObjectURL(f)} height="60" /></td>
            <td>{f.name}</td>
            <td>{f.size}</td>
            <td>{f.type}</td>
          </tr>
        );
      })}
      </tbody>
    </table>
  );
}

Finally the "brains" or the non-render methods of the App component:

constructor() {
  super();
  this.state = {
    files: [],
  };
  document.documentElement.ondragenter = e => e.preventDefault();
  document.documentElement.ondragover = e => e.preventDefault();
  document.documentElement.ondrop = e => {
    e.preventDefault();
    this.update(e.dataTransfer.files); // dropped files
  }
}

handleUploads(e) { 
  this.update(e.target.files); // from file input
}

update(moreFiles) {
  const files = Array.from(moreFiles);
  if (!files) {
    return;
  }
  this.setState({
    files: this.state.files.concat(files)
  });
}

As you can see all we need to do is maintain the list of files in the state and all comes to place.

The constructor also takes care of setting up drag-drop listeners.

C'est tout!

Once again - code and demo.

I'd be thrilled if anyone uses this as a jumping point to create different tools. We can never have too many tools!

Oh yeah - and if you want to learn React in 2017 just buy my book ??

Update: Part 2 where the app becomes a PWA

Tell your friends about this post: Facebook, Twitter, Google+

Sorry, comments disabled and hidden due to excessive spam. Working on restoring the existing comments...

Meanwhile, hit me up on twitter @stoyanstefanov


  • “四新”彰显党的十九大思想灵魂和精髓要义 2018-08-17
  • 热身赛-U17女篮73-68立陶宛 杨舒宇19分刘禹彤13分 2018-08-16
  • 七月流火:一半是甜蜜 一半是仁慈 2018-08-15
  • “嫦娥”飞向月球背面,将会揭开哪些秘密? 2018-08-15
  • 一代枭雄身后事:“曹操墓”认定过程缘何一波三折? 2018-08-04
  • 女出纳侵吞千万公款扮富婆 7年未被公司发现 2018-08-04
  • 南昌PM2.5浓度写进目标责任书 切实防治大气污染 2018-07-20
  • 网友投诉不文明养犬行为 有关部门加强治理 2018-07-20
  • 562| 529| 331| 850| 175| 76| 766| 346| 198| 527|