React入门系列一

2,116 阅读21分钟

近期开始入门react,对于我这样的前端码畜来讲
Q: 入门最好的方式是什么?(黑人问号脸)
A: 当然是看文档呀!!!
ps:我已经断断续续看了一星期的官方文档,总体来讲,我觉得文档写的很详细,详细的程度以致于我觉得有很多啰嗦的话(哈哈),所以一边敲案例,一边做自己的总结性的归纳。 附:大佬的对话,说的还是有道理的

jsx

1.在 JSX 当中的表达式要包含在大括号里

2.书写 JSX 的时候一般都会带上换行和缩进,这样可以增强代码的可读性

3.推荐在 JSX 代码的外面扩上一个小括号,这样可以防止 分号自动插入的 bug

4.JSX 标签是闭合式的,那么你需要在结尾处用 />, 就好像 XML/HTML 一样

//定义对象数据,给下面面类似"纯函数的组件"使用
const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};
//jsx中调用此函数表达式
function formatName(user) {
  return user.firstName + ' ' + user.lastName;
};
// jsx换行缩进,增强可读性
const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>  {/* JSX标签是闭合式的 */}
);
// 渲染元素
ReactDOM.render(
  element,
  document.getElementById('root')
);

5.Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用。

const element = <h1 className="greeting">Hello, world!</h1>;
//两种代码的作用是完全相同
const element = React.createElement(
  "h1",
  { className: "greeting" },
  "Hello, world!"
);

6.JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小驼峰命名 来定义属性的名称,而不是使用 HTML 的属性名称

//class 变成了 className,而 tabindex 则对应着 tabIndex
function App(props) {
  return (
    <div className="Comment" tabIndex="1">
      {/*
                         do something   
                    */}
    </div>
  );
}

元素渲染

  1. 元素是构成 React 应用的最小单位。
  2. 元素事实上只是构成组件的一个部分
  3. 在实际生产开发中,大多数 React 应用只会调用一次 ReactDOM.render()
  4. React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。

组件 & Props

  1. 组件从概念上看就像是函数,它可以接收任意的输入值(称之为“props”),并返回一个需要在页面上展示的 React 元素。

  2. 函数组件

    function Welcome(props) {
      return <h1>Hello, {props.name}</h1>;
    }
    
  3. 类组件

    class Welcome extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    
  4. 遇到的 React 元素都只是 DOM 标签,也可以是用户自定义的组件,当 React 遇到的元素是用户自定义的组件,它会将 JSX 属性作为单个对象传递给该组件,这个对象称之为“props”。

    class AppComponent extends React.Component {
      render() {
        return <h1>This is class define component: {this.props.name}</h1>;
      }
    }
    //组件名称必须以大写字母开头。<div /> 表示一个DOM标签,但 <App /> 表示一个组件
    ReactDOM.render(
      <AppComponent name="ReactApp" />,
      document.getElementById("root")
    );
    
  5. 通常,一个新的 React 应用程序的顶部是一个 App 组件。但是,如果要将 React 集成到现有应用程序中,则可以从下而上使用像 Button 这样的小组件作为开始,并逐渐运用到视图层的顶部。

    
      function Welcome(props){
            return <h1>Hello, {props.name}</h1>
        }
        class App extends React.Component {
            render() {
                return (
            {
                /*
                组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<Welcome />元素的原因。
                */
             }
                    <div>
                        <h1>This is class define component: {this.props.name}</h1>
                        <Welcome name="1111" />
                        <Welcome name="2222" />
                        <Welcome name="3333" />
                    </div>
                )
            }
        }
        ReactDOM.render(<App name="ReactApp" />,document.getElementById("root"))
    

State & 生命周期

React 是非常灵活的,但它也有一个严格的规则:所有的 React 组件必须像纯函数那样使用它们的 props。何为纯函数? 字面意思就是给你什么返回什么,不关注函数内部的东西,引用函数式编程里面的一句话:所有纯函数必须遵守引用透明性

状态与属性十分相似,但是状态是私有的,完全受控于当前组件。

封装时钟(函数组件)

//封装时钟, 理想情况下,我们写一次 Clock 然后它能更新自身,为了实现这个需求,我们需要为Clock组件添加状态
function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}
function tick() {
  ReactDOM.render(<Clock date={new Date()} />, document.getElementById("root"));
}
setInterval(tick, 1000);

类组件实现

Clock 现在被定义为一个类而不只是一个函数,使用类就允许我们使用其它特性,例如局部状态、生命周期钩子

//将函数转换为类
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

//为一个类添加局部状态State
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date(),
      name: this.props.name //将props存入state
    };
  }
  render() {
    return (
      <div>
        <h1>hello,React!</h1>
        <h2>this is Clock component:{this.state.date.toLocaleTimeString()}</h2>
        <h3>{this.props.name}</h3>
        <h3>{this.state.name}</h3>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock name="这是我自定义的props:name" />,
  document.getElementById("root")
);

类组件中加入 React 的生命周期方法

  1. 在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。
  2. 第一次加载到 DOM 中的时候叫作挂载,vue 中采用$mount("#app")
  3. OM 被移除的时候叫作卸载

我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      date: new Date(),
      name: this.props.name
    };
  }
  //生命周期钩子
  componentDidMount() {
    this.timerID = setInterval(() => this.tick(), 1000);
  }
  //生命周期钩子
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  tick() {
    //调用 setState() 来调度UI更新
    this.setState({
      date: new Date()
    });
  }
  render() {
    return (
      <div>
        <h1>hello,React!</h1>
        <h2>this is Clock component:{this.state.date.toLocaleTimeString()}</h2>
        <h3>{this.props.name}</h3>
        <h3>{this.state.name}</h3>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock name="这是我自定义的props:name" />,
  document.getElementById("root")
);

State 正确使用

1.不要直接更新状态

应当使用 setState(),构造函数是唯一能够初始化 this.state 的地方。

2.状态更新可能是异步的

React 可以将多个 setState() 调用合并成一个调用来提高性能。this.props 和 this.state 可能是异步更新的,你不应该依靠它们的值来计算下一个状态。请使用第二种形式的 setState() 来接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将此次更新被应用时的 props 做为第二个参数:

// es6大括号解释为块代码,如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则报错
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});
3.状态更新合并

当你调用 setState() 时,React 将你提供的对象合并到当前状态。

class CommentApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      user: "eastboat1",
      comments: [
        { id: 1, content: "这是评论1" },
        { id: 2, content: "这是评论2" },
        { id: 3, content: "这是评论3" }
      ]
    };
  }
  //生命周期钩子
  componentDidMount() {
    //模拟异步数据修改state ,独立更新对应的state
    setTimeout(() => {
      this.setState({
        user: "eastboat2"
      });
    }, 3000);
  }
  componentWillUnmount() {}
  render() {
    return (
      <div>
        <h2>this is my component:CommentApp</h2>
        <h2>{this.state.user}</h2>
        <h2>{this.props.UserName}</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <CommentApp UserName="这是我自定义的props:UserName" />,
  document.getElementById("root")
);

数据流向(单向流)

组件可以选择将其状态作为属性传递给其子组件:这通常被称为自顶向下或单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。

事件处理

通常建议在构造函数中绑定或使用属性初始化器语法来避免这类

  1. React 事件绑定属性的命名采用驼峰式写法,而不是小写
  2. 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是一个字符串(DOM 元素的写法)
//原生html中
<button onclick="handleChange">点击按钮</button>

//react
<button onClick={handleChange}>点击按钮</button>
  1. 在 React 中另一个不同是你不能使用返回 false 的方式阻止默认行为。你必须明确的使用 preventDefault
//类组件中 不能使用返回 false 的方式阻止默认行为
class App extends React.Component {
  render() {
    function handleClick(e) {
      e.preventDefault();
      console.log("The link was clicked.");
    }
    return (
      <a href="www.baidu.com" onClick={handleClick}>
        a标签
      </a>
    );
  }
}
类的方法
  1. 使用 React 的时候通常你不需要使用 addEventListener 为一个已创建的 DOM 元素添加监听器。你仅仅需要在这个元素初始渲染的时候提供一个监听器。
class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isToggleOn: true
    };
    this.handleClick = this.handleClick.bind(this);
  }
  //类方法,但是类的方法默认是不会绑定 this 的,需要上面的bind
  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? "ON" : "OFF"}
      </button>
    );
  }
}
属性初始化器语

这种语法确保this绑定在 handleClick 中

class LoggingButton extends React.Component {
  handleClick = () => {
    console.log("this is:", this);
  };
  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}
回调函数中使用箭头函数
class LoggingButton extends React.Component {
  handleClick() {
    console.log("this is:", this);
  }

  render() {
    return <button onClick={e => this.handleClick(e)}>Click me</button>;
  }
}
向事件处理程序传递参数
//二者等价
//箭头函数的方式,事件对象必须显式的进行传递
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

//bind 的方式,事件对象以及更多的参数将会被隐式的进行传递
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面

class App extends React.Component {
  constructor() {
    super();
    this.state = { name: "Hello world!" };
  }
  preventPop(name, e) {
    //事件对象e要放在最后
    e.preventDefault();
    alert(name);
  }
  render() {
    return (
      <div>
        <p>hello</p>
        <a
          href="https://reactjs.org"
          onClick={this.preventPop.bind(this, this.state.name)}
        >
          Click
        </a>
      </div>
    );
  }
}

条件渲染

if 条件判断

使用 JavaScript 运算符 if 或者条件运算符去创建元素来表现当前的状态

//组件一
function ComponentOne() {
  return <h1>this is component one</h1>;
}
//组件二
function ComponentTwo() {
  return <h1>this is component two</h1>;
}
//容器组件
function App(props) {
  const status = props.isLoginStatus;
  if (status) {
    return <ComponentOne />;
  } else {
    return <ComponentTwo />;
  }
}
使用元素变量存储元素
function LoginButton(props) {
  return <button onClick={props.onClick}>登录</button>;
}

function LogoutButton(props) {
  return <button onClick={props.onClick}>登出</button>;
}
class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLoginClick.bind(this);
    this.state = {
      isLoginStatus: false
    };
  }
  handleLoginClick() {
    //登录
    this.setState({
      isLoginStatus: true
    });
  }
  handleLogoutClick() {
    //登出
    this.setState({
      isLoginStatus: false
    });
  }

  render() {
    const status = this.state.isLoginStatus;
    let button; //创建变量存储组件元素
    if (status) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }
    return <div>{button}</div>;
  }
}
与运算符 &&

在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。如果条件是 true,&& 右侧的元素就会被渲染,如果是 false,React 会忽略并跳过它。

const arr = ["a", "b", "c"];
function App(props) {
  const list = props.list;
  return <div>{list.length > 0 && <h1>这是list列表</h1>}</div>;
}
ReactDOM.render(<App list={arr} />, document.getElementById("root"));
三目运算符
//文本渲染使用
return (
  <div>
    The user is <b>{isLoggedIn ? "currently" : "not"}</b> logged in.
  </div>
);
//组件渲染使用
return (
  <div>
    {isLoggedIn ? (
      <LogoutButton onClick={this.handleLogoutClick} />
    ) : (
      <LoginButton onClick={this.handleLoginClick} />
    )}
  </div>
);
阻止组件渲染
  1. 可以让 render 方法直接返回 null,而不进行任何渲染
  2. 在组件的 render 方法中返回 null 并不会影响组件的生命周期
function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return <div className="warning">Warning!</div>;
}

列表 && key

map() 函数
// map() 不会对空数组进行检测
// map() 不会改变原始数组。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number * 2);
// [2, 4, 6, 8, 10]
key 用作确定的标识
  1. 一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据 id 来作为元素的 key
  2. 如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题
class App extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const list = this.props.listitem;
    const ListItem = list.map((val, index, arr) => {
      return <li key={index}>{val}</li>;
    });
    return (
      <div>
        <ul>{ListItem}</ul>
      </div>
    );
  }
}
const arr = ["a", "b", "c", "d", "e"];
ReactDOM.render(<App listitem={arr} />, document.getElementById("root"));
  1. 元素的 key 只有放在就近的数组上下文中才有意义。
function ListItem(props) {
  // 正确!这里不需要指定 key:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map(number => (
    // 正确!key 应该在数组的上下文中被指定
    <ListItem key={number.toString()} value={number} />
  ));
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById("root")
);
  1. key 只是在兄弟节点之间必须唯一

    数组元素中使用的 key 在其兄弟节点之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的 key 值:

JSX 中嵌入 map()
function ListItem(props) {
  return <li>{props.value}</li>;
}
class App extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const list = this.props.listitem;
    return (
      <div>
        <ul>
          {/*此处是jsx中的写法*/
          list.map((val, index, arr) => (
            <ListItem value={val} key={index} />
          ))}
        </ul>
      </div>
    );
  }
}
const arr = ["a", "b", "c", "d", "e"];
ReactDOM.render(<App listitem={arr} />, document.getElementById("root"));

表单

在 React 里,HTML 表单元素的工作方式和其他的 DOM 元素有些不同,这是因为表单元素通常会保持一些内部的 state

受控组件

表单元素通常自己维护 state,并根据用户输入进行更新,而可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新,两者结合起来,使得 React 的 state 成为“唯一数据源,渲染表单的 React 组件还控制着用户输入过程中表单发生的操作,这种表单输入元素就叫做“受控组件”。

class MyFormComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "初始化state内容" };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(e) {
    this.setState({
      value: e.target.value
    });
  }
  handleSubmit(e) {
    e.preventDefault();
    console.log(e.target);
    console.log(this.state.value);
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.value}
          onChange={this.handleChange}
        />
        <input type="submit" value="提交" />
      </form>
    );
  }
}

ReactDOM.render(<MyFormComponent />, document.getElementById("root"));
textarea 标签

在 HTML 中, textarea 元素通过其子元素定义其文本,而在 React 中,textarea 使用 value 属性代替,和上面的 input 一样绑定 value 属性

select 标签

React 并不会使用 selected 属性,而是在根 select 标签上使用 value 属性

//可以将数组传递到 value 属性中,以支持在 select 标签中选择多个选项
<select multiple={true} value={['B', 'C']}>
处理多个输入

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作

状态提升

多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去

  1. 在React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”
  2. 应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state。

组合VS继承

推荐使用组合而非继承来实现组件间的代码重用

在 React 中没有“槽”这一概念的限制,你可以将任何东西作为 props 进行传递

  1. 使用一个特殊的 children prop 来将他们的子组件传递到渲染结果中
    function App(props) {
      return (
        <div>
          {props.children}  //渲染子组件
        </div>
      );
    }
    //组件中的子组件内容
      function ParentComponent() {
        return (
           <App>
              <p>这是子组件内容</p>
              <p>这是子组件内容</p>
              <p>这是子组件内容</p>
          </App>
        );
      }
    
  2. 少数情况下,你可能需要在一个组件中预留出几个“洞”。这种情况下,我们可以不使用 children,而是自行约定:将所需内容传入 props,并使用相应的 prop。
     function App(props) {
       return (
         <div>
             <div className='CommOne'>
                 { props.left }
             </div>
             <div className='CommTwo'>
                 { props.right }
             </div>
         </div>
       );
     }
     //  如  <leftComponent />  <rightComponent /> React 元素本质就是对象(object)
     function ParentComponent() {
       return (
         <App 
             left={
               <leftComponent />
             }
             right={
               <rightComponent />
             }  
         />
         );
     }
    

Props 和组合为你提供了清晰而安全地定制组件外观和行为的灵活方式。注意:组件可以接受任意 props,包括基本数据类型,React 元素以及函数

如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们

React哲学

我们平时在公司中,都会和UI小姐姐(小哥哥)对接,做项目时首先拿到项目的UI设计稿,这时候我们就需要站在组件的维度去思考这个UI设计稿。

1.划分为组件层级

根据UI设计稿划分为组件层级,以合适的名称命名,UI(组件结构)和数据模型都会倾向于遵守相同的信息结构,所以UI和JSON数据模型一一对应

Q:如何确定应该将哪些部分划分到一个组件中呢?
A:可以将组件当作一种函数或者是对象来考虑,
  根据单一功能原则来判定组件的范围。
  也就是说,一个组件原则上只能负责一个功能。
2.编写静态的组件
  1. 先用已有的数据模型渲染一个不包含交互功能的 UI
  2. 最好将渲染 UI 和添加交互这两个过程分开,因为往往要编写大量代码,而不需要考虑太多交互细节,而添加交互功能时则要考虑大量细节,不需要编写太多代码
  3. 当你的应用比较简单时,使用自上而下的方式更方便;对于较为大型的项目来说,自下而上地构建,并同时为低层组件编写测试是更加简单的方式。
  4. state 代表了随时间会产生变化的数据,应当仅在实现交互时使用。所以构建应用的静态版本时,你不会用到它
3.确定所需的state 的最小集合

通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state

1.该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
2.该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
3.你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
4.确定 state 放置的位置

上面已经确定了应用所需的 state 的最小集合。接下来,我们需要确定哪个组件能够改变这些 state,或者说拥有这些 state。

1.找到根据这个 state 进行渲染的所有组件。
2.找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
3.该共同所有者组件或者比它层级更高的组件应该拥有该 state。
4.如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置。
5.于高于共同所有者组件层级的位置。
5.添加反向数据流( setState )

React 通过一种比传统的双向绑定略微繁琐的方法来实现反向数据传递。尽管如此,但这种需要显式声明的方法更有助于人们理解程序的运作方式。 我们通过setState()函数让数据反向传递:处于较低层级的表单组件更新较高层级中的state。

至此react文档基本核心内容已看完,再也不用担心被T掉了

ES6常用知识准备

1. const 和 let

请移步我之前写的文章使用const声明常量或者阮大大

2. 对象属性和方法

const person = {
    name: "Eastboat",
    walk:function() {
        //es5写法
    }
    speack(){
        //es6
    }
}
person.walk()
person.name="cc01"
person['name']="cc02"

3. this 指向问题

const person = {
    name: "Eastboat",
    speack(){
        console.log(this);
    }
}
person.speak() //this指向person对象 输出对象

const speakCopy=person.speak;
speakCopy()
//调用指向全局window,但是此处输出的是undefined,
//因为react中严格模式是默认开启的

4.bind()

通过 bind()绑定 this

const person = {
  name: "Eastboat",
  speack() {
    console.log(this);
  }
};
person.speak();
//bind方法会返回一个新的函数实例,然后把这个实例的this指向person对象
const speakCopy = person.speak.bind(person); //此处函数也是个对象
speakCopy(); //此处调用就修正了this的指向

5.箭头函数

const square = function(number) {
  return number * number;
};
//es6写法
const square = number => number * number;

//案例:
const jobList = [
  { id: 1, isActive: true },
  { id: 2, isActive: false },
  { id: 3, isActive: true }
];
const activeJob = jobList.filter(function(job) {
  return job.isActive;
});

const activeJob = jobList.filter(job => job.isActive);

箭头函数可以穿透获取 this

/*
   setTimeOut中的回调函数在严格模式下不会设置为undefined而是指向window

   解决办法:创建临时变量 var self=this;
*/
const person = {
  name: "Eastboat",
  speack() {
    var self = this;
    setTimeout(function() {
      console.log(this); //window
      console.log(self); //person
    }, 1000);
  }
};
person.speak();

//ES6箭头函数穿透会获取this,不用绑定一个变量
setTimeout(() => {
  console.log(this); //person
}, 1000);

6.map方法

map() 不会对空数组进行检测,不会改变原始数组

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number * 2);
// [2, 4, 6, 8, 10]

7.对象解构

//原始写法
const address = {
  street: "",
  city: "",
  country: ""
};
const street = address.street;
const city = address.city;
const country = address.country;

//利用解构,
const { steet, city, country } = address;

//自定义获取的变量

const { street: st, city: ct, country: cty } = address;

8.展开运算符

  1. 数组
const arrOne = [1, 2, 3];
const arrTwo = [4, 5, 6];
const arrAll = arrOne.concat(arrTwo); // 使用concat方法合并
const arrAll = [...arrOne, ...arrTwo]; //扩展运算符,好处是我们可以在中间插入值
  1. 对象
const objOne = { name: "one" };
const objTwo = { name: "two" };
const objAll = { ...objOne, ...objTwo }; //可加入其他属性

const cloneObj = { ...objOne }; //克隆一个对象

9.class

react中有函数组件和类组件,ES6支持通过class定义类,贴近java语法,如果对js面向对象(OOP)这一块想作了解的话,请移步我之前写的《JavaScript高级程序设计》OOP章节的总结

//帕斯卡命名法。单词首字母大写
 class CoolPerson {
     constructor(name){
         this.name=name
     }
     speak(){
         console.log('说话')
     }
 }
 const person=new CoolPerson('eastboat')

 class Teacherextends CoolPerson {
     constructor(name,degree) {
         super(name); //引用基类的构造器
         this.degree=degree;
     }
     teach() {
         console.log('讲课')
     }
 }
 const teacherPerson=new Teacher('jack','博士')
 teacherPerson.speak() //继承了Person的方法和属性

10.模块-ES6 Module

ECMAScript6 标准增加了 JavaScript 语言层面的模块体系定义。如果对模块化演变不是很明白的同学请移步这里,本身Node.js是一个高度模块化的平台,学习模块化可以帮助我们快速理解和使用Node.js

// 拆分上面代码为模块,每个文件对应一个模块

//person.js
export class CoolPerson {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log("说话");
  }
}

//teacher.js
import { CoolPerson } from "./person";
export class Teacher extends CoolPerson {
  constructor(name, degree) {
    super(name); //引用基类的构造器
    this.degree = degree;
  }
  teach() {
    console.log("讲课");
  }
}

//index.js
import { Teacher } from "./teacher";
const teacherPerson = new Teacher("jack", "博士");
teacherPerson.speak(); //继承了Person的方法和属性

#####以名导入

// Teacher.js下导出的对象或方法
export class Teacher {}
export class Student {}

//从模块中导入的不止是一个,所以用{}
import { Teacher, Student } from "./Teacher.js";
默认导出
//只有一个对象需要导出时候就可以使用默认导出
export default class Teacher extends CoolPerson {
  //....
}
//引入 Teacher为默认导出的对象的名字
import Teacher from "./Teacher";
混合使用
//Teacher.js下导出的对象或方法
export default class Teacher {}
export function fn() {}

//导入
import Teacher, { fn } from "./Teacher";
//react中,react为公共模块, React是react默认导出的对象,Component是一个以名导出的对象
import React, { Component } from "react";

create-react-app脚手架

react生态已经足够丰富了,比较常用的解决方案 dva(基于 React 和 redux,具有 elm 风格的轻量级框架。),Umi(可插拔的企业级 React 应用框架),Taro(一套遵循 React 语法规范的多端统一开发框架),但是对于入门来讲,还是先从最基本的东西开始吧,慢慢的进步,其实不难发现学习就是一个刷新自我认知的过程

//es6新特性 写jsx
const element = <h1>Hello React</h1>;

/*
通过abel转换后如下:其实是调用了React.createElement()生成节点
注意: react中书写组件,最外层必须有一个顶层元素包裹起来,
      否则React.createElement()第一个参数无法识别,
      Fragment可以去掉最外层无用的div
*/
("use strict");
var element = React.createElement("h1", null, "hello React");

create-react-app脚手架创建的项目几乎是零配置的,如果你是一位进阶开发者,你可能会自己配置 webpack,这时候就需要 eject 命令了

//我们在package.json下面看不到任何webpack或babel的引用,所有复杂性都隐藏了
 "dependencies": {
    "react": "^16.8.6",  //主要库
    "react-dom": "^16.8.6",  //渲染浏览器的DOM 如 render()
    "react-scripts": "3.0.1"  //进行下面scripts命令的库
  },
  "scripts": {
    "start": "react-scripts start", //开启开发环境
    "build": "react-scripts build", // 创建生产环境(打包)
    "test": "react-scripts test",   //测试程序的模块和功能
    //将已生成的程序弹出,就可以自行配置所有程序相关的属性,这个结果是不可逆的
    //如果进行eject命令,我们就能看到所有的依赖细节
    "eject": "react-scripts eject"
  },