广西快乐双彩中奖号码: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.

Meanwhile, hit me up on twitter @stoyanstefanov


  • 76人参加高山滑雪跨界跨项选材测试 或进冬奥备战梯队 2019-05-18
  • 不是特效!上港队长一脚踢中海鸥 这脚法简直坑爹 2019-05-08
  • 新疆坚决打好污染防治攻坚战 2019-05-07
  • 高考在即,晋中市招生考试管理中心提醒广大考生及家长要把握好高考“四个趋势” 2019-04-25
  • 运城市在长三角招商引资149.9亿元 2019-04-08
  • 济南五胞胎雪虎宝宝亮相 四雌一雄萌态十足 2019-04-08
  • 去产能迎年中考 煤炭、钢铁企业债务问题依然存在 2019-04-07
  • 最高检等四部门出台意见 指导依法办理恐怖活动和极端主义犯罪案件 2019-04-07
  • 广州市黄埔区人民法院公告专栏 2019-03-28
  • 这个“海之宁”是个死抱着相对论旧谬误不放,疯狂反对科学新真理的跳梁“小丑”,这个跳梁“小丑”根本就不懂得尊重客观事实及其规律,总是无视、脱离、歪曲客观... 2019-03-22
  • 如何理解孔子这句话?北大教授胡军动情论生死 2019-03-21
  • 海外舆论关注中国最新军备 称赞习近平主席强军号令 2019-03-19
  • 女性之声——全国妇联 2019-03-19
  • 美司法部科米在希拉里邮件门调查中存在过失 2019-03-17
  • “四新”彰显党的十九大思想灵魂和精髓要义 2018-08-17
  • 423| 367| 888| 451| 948| 651| 154| 838| 823| 332|