从0搭建React项目

参考网址:https://www.jianshu.com/p/324fd1c124ad
看过很多react的入门文章,上面的这一篇链接是看过最好的了,不过依旧会有一些跳跃,刚入门的小伙伴参照进行练习时难免会卡住,特重新整理一遍,既加强自己的记忆,又能帮助到其它小伙伴。

基础篇,搭建

项目目录创建,及必备依赖安装

(这篇文章的前提是node.js你已经安装过了,如果不会的话可以留言,手把手教你)

mkdir my-react
cd my-react

#生成 package.json 文件.
npm init 

#安装各种依赖
npm install --save react react-dom 
npm install --save webpack webpack-dev-server webpack-cli
npm install --save babel-core babel-cli babel-polyfill babel-loader babel-runtime babel-plugin-transform-runtime  babel-preset-es2015 babel-preset-react babel-preset-stage-2

修改package.json

添加下面的scripts内容

"scripts": {
  "dev": "webpack-dev-server --mode production ",
  "build": "webpack  --mode production"
}

命令行输入 npm run dev 将要启动webpack-dev-server
命令行输入 npm run build 将会进行生产环境打包

启动webpack

至此,React项目已经搭建好了,启动吧

npm run dev

浏览器效果

这个时候打开浏览器访问 localhost:8080/就可以看到东东了
这里写图片描述

进阶篇,使用React创建类

在my-react目录中创建index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
  <div id="app"></div>
  <script src="bundle.js"></script>
</body>
</html>

创建app.js,webpack.config.js

在my-react目录中创建子目录src,在src中创建文件app.js,内容如下

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
  render(){ // Every react component has a render method.
    return( // Every render method returns jsx. Jsx looks like HTML, but it's actually javascript and functions a lot like xml, with self closing tags requiring the `/` within the tag in order to work propperly
      <div>
        Hello World
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));

在my-react目录中创建webpack.config.js,内容如下
该文件名是默认命名,如果叫其它名字,比如webpack.config.prod.js,则需要在script中进行显性指定
“build”: “webpack –mode production webpack.config.prod.js”

var webpack = require('webpack');
module.exports = {
  entry: './src/app.js',        //默认配置:./src/index.js
  output: {
      path: __dirname + '/build', //默认配置:/dist
      filename: "bundle.js"       //默认配置:main.js
  },
  module: {
      rules: [{
          test: /\.js$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          query: {
              plugins: ['transform-runtime'],
              presets: ['es2015', 'react', 'stage-2']
          }
      }, {
          test: /\.css$/,
          loader: "style-loader!css-loader"
      }]
  }
};

浏览器效果

这里写图片描述

实战篇:创建可复用的组件

创建components组件

在my-react目录中创建components文件夹,并在components文件夹中创建文件 ToDoApp.js

import React from 'react';
class ToDoApp extends React.Component {
  render() {
    return (
      <div>To Do App</div>
    );
  }
}

export default ToDoApp;

重新编辑my-react/src/app.js

import React from 'react';
import ReactDOM from 'react-dom';
import ToDoApp from '../components/ToDoApp';

class App extends React.Component {
  render(){ // Every react component has a render method.
    return( // Every render method returns jsx. Jsx looks like HTML, but it's actually javascript and functions a lot like xml, with self closing tags requiring the `/` within the tag in order to work propperly
      <div>
        <div>Hello World</div>
        <ToDoApp />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));

浏览器效果

这里写图片描述

进一步迭代app.js return方法里内容

import React from 'react';
import ReactDOM from 'react-dom';
import ToDoApp from '../components/ToDoApp';

class App extends React.Component {
  render(){ // Every react component has a render method.
    return( // Every render method returns jsx. Jsx looks like HTML, but it's actually javascript and functions a lot like xml, with self closing tags requiring the `/` within the tag in order to work propperly
        <div className="row">
          <div className="col-md-10 col-md-offset-1">
            <div className="panel panel-default">
              <div className="panel-body">
                <h1>My To Do App</h1>
                <hr/>
                List goes here.
              </div>
            </div>
          </div>
        </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));

浏览器效果

这里写图片描述

接下来搞个真实的列表

创建my-react/components/List.js,内容如下:

import React from 'react';

const List = (props) => {

  const list = props.listItems.map((el, i)=>(
    <li key={i}><h2>{el}</h2></li>
  ));

  return (
    <div>
      <ul>
        {
          list
        }
      </ul>
    </div>
  )
};

export default List;

修改my-react/components/ToDoApp.js,内容为:

import React from 'react';
import List from '../components/List';

class ToDoApp extends React.Component {

  componentWillMount(){ // run before the render method
    this.setState({ // add an array of strings to state.
      list: ['thing1', 'thing2', 'thing3']
    })
  };

  render() {
    return (
      <div>
        <div>aaaa</div>
          <List listItems={this.state.list} />
      </div>
    );
  }
}

export default ToDoApp;

浏览器效果

这里写图片描述

给APP添加功能

创建my-react/components/Input.js,内容如下

import React from 'react';

class Input extends React.Component {
  render() {
    return (
      <div>
        <form>
          <div
            className="form-group">
            <label
              htmlFor="listInput">
              Email address
            </label>
            <input
              type="text"
              className="form-control"
              id="listItemInput"
              placeholder="Add new todo"
            />
            <button
              className="btn btn-primary">
              Add Item
            </button>
          </div>
        </form>

      </div>
    );
  }
}

export default Input;

修改my-react/components/ToDoApp.js,内容为:

import React from 'react';
import List from '../components/List';
import Input from '../components/Input';

class ToDoApp extends React.Component {

  componentWillMount(){ // run before the render method
    this.setState({ // add an array of strings to state.
      list: ['thing1', 'thing2', 'thing3']
    })
  };

  render() {
    return (
      <div>
        <Input />
      </div>
    );
  }
}

export default ToDoApp;

这时候会发现一个输入框和按钮的视图,这个组件的静态视图已经写好了,下面就需要添加功能了。

首先我们需要做的是如何获取输入框的值,因为这个输入框的值需要在其他组件中获取,所以我们并不想要在Input组件中来处理这个数据存储。事实上,在子组件中存储数据在任何时候都是不推荐的,我们应该将数据存储在app的顶端组件并且通过props传递下来。

另一个需要记住的是即使我们目前把数据存储在了上层的 ToDoApp 组件,后期还是会用redux来代替来处理整个app的数据。这里先仅仅使用react的state来实现。

ok,我们在ToDoApp的 componentWillMount的setState中新增一个newToDo属性用来存储输入框的值。

好了,直接看代码吧
修改my-react/components/ToDoApp.js,内容为:

import React from 'react';
import List from '../components/List';
import Input from '../components/Input';

class ToDoApp extends React.Component {

  componentWillMount() {
    this.setState({
      list: ['thing1', 'thing2', 'thing3'],
      newToDo: 'test'
    })
  } ;

  handleChange=(event) =>{
    console.log("aa", event.target.value ) 
    this.setState({ newToDo: event.target.value});

  };

  handleClick =(event) =>{
    console.log("bb" ,event.target.value ) 

    event.preventDefault();
    this.setState((previousState)=>({
      list: [...previousState.list, previousState.newToDo ],
      newToDo: ''
    }));

  };

  render() {
    return (
      <div>
        <Input newToDo={this.state.newToDo } updateStateProp={this.handleChange} updateStateClick={this.handleClick }/>

        <List listItems={this.state.list } />
      </div>
    );
  }
}

export default ToDoApp;

修改my-react/components/Input.js,内容如下:

import React from 'react';

class Input extends React.Component {
  render() {
    return (
      <div>
        <form>
          <div
            className="form-group">
            <label
              htmlFor="listInput">
              Email address
            </label>
            <input
              type="text"
              className="form-control"
              id="listItemInput"
              placeholder="Add new todo"
              value={this.props.newToDo }
              onChange={this.props.updateStateProp }
            />
            <button
              className="btn btn-primary" onClick={this.props.updateStateClick } >
              Add Item
            </button>
          </div>
        </form>

      </div>
    );
  }
}

export default Input;

备注:还没有搞明白修改newToDo 与list 的方式为什么不一致

this.setState((previousState)=>({
list: […previousState.list, previousState.newToDo ],
newToDo: ”
}));
为什么不直接这样呢,简书上有解释却没有看明白
this.setState((previousState)=>({
list: previousState.list.push(previousState.newToDo) ;
newToDo: ”
}))

简书就此问题描述如下:
正如我上面的描述,最开始写state的时候很多人都会犯这样的错误,直接用push这样的方法,修改了state,这样就不算immutable的,我们一定要保证绝不直接修改原state。

浏览器效果

看看效果吧
这里写图片描述

项目源代码

整个项目我都放置到github上了,有兴趣的话可以下载下来看看
https://github.com/lzc-alioo/my-react

猜你喜欢

转载自blog.csdn.net/hl_java/article/details/80382890