React学习(二)

学习过程中自己弄得小项目

在线预览

整理过程中遇到了好用的前端js库:

immutable(持久化数据结构、结构共享):

NPM 地址

Immutable 详解及 React 中实践 · Issue #3 · camsong/blog

classnames(支持对className的逻辑操作):

NPM地址

 

1.React 安装

使用Facebook提供的 create-react-app 脚手架工具构建react项目

create-react-app 是来自于 Facebook,通过该命令我们无需配置就能快速构建 React 开发环境。

create-react-app 自动创建的项目是基于 Webpack + ES6 。

配置 npm 的registry 下载package更快

$ npm config set registry https://registry.npm.taobao.org

 配置后可通过下面方式来验证是否成功

$ npm config get registry

 create-react-app构建启动项目

$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
$ npm start

附:create-react-app github地址

2.JSX语法    

一种 JavaScript 的语法扩展。 推荐在 React 中使用 JSX 来描述用户界面

可以任意地在 JSX 当中使用 JavaScript 表达式,在 JSX 当中的表达式要包含在大括号里。

React DOM 在渲染之前默认会 过滤 所有传入的值。它可以确保你的应用不会被注入攻击。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(跨站脚本) 攻击。

如果你已经有了个 props 对象,并且想在 JSX 中传递它,你可以使用 ... 作为扩展操作符(Spread syntax)来传递整个属性对象。下面两个组件是等效的:

function App1() {
  return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}

 

警告:
    因为 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小驼峰命名 来定义属性的名称,而不是使用 HTML 的属性名称。
    例如,class 变成了 className,而 tabindex 则对应着 tabIndex。
3.state & props & render

state:

构造函数是唯一能够初始化 this.state 的地方

修改state通过this.setState({comment: 'Hello'})

状态更新可能是异步的,要是修改state的变量依赖本身,需要通过setState的callback解决:

  incrementCount() {
    const me = this;
    me.setState((prevState) => {
      return { count: prevState.count + 1 }
    });
    //ERROR
    // me.setState({
    //   count : me.state.count + 1
    // });
  }

  incrementTwo() {
    const me = this;
    me.incrementCount();
    me.incrementCount();
  }

 props:

 无论是使用函数或是类来声明一个组件,它决不能修改它自己的props

{props.children}获取包含的子组件列表

render:

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

组件的返回值只能有一个根元素。这也是我们要用一个<div>来包裹所有<h1/><h2/>元素的原因。

布尔值、Null 和 Undefined 被忽略渲染时会被忽略

<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>

4.keys

React提供key属性,来提高元素变更之后重新渲染的效率

Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。

一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用来自数据的id作为元素的key

如果列表可以重新排序,我们不建议使用索引来进行排序,因为这会导致渲染变得很慢

不能通过props.key获取key的值。

举个例子:

<li>a</li>
<li>b</li>

 改变后:

<li>c</li>
<li>a</li>
<li>b</li>

肉眼很容易看出来在第一行加了一个 c ,但React并不知道,而是一行一行的比较(a 与 c),所以需要在每个 li 都一个 key ,利于React辨别,从而提供效率


5.form 表单使用

html:
<textarea>
  Hello there, this is some text in a text area
</textarea>

jsx:
<textarea value={this.state.value} onChange={this.handleChange} />


html:
<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

jsx:
<select value={this.state.value} onChange={this.handleChange}> 
	<option value="grapefruit">Grapefruit</option> 
	<option value="lime">Lime</option> 
	<option value="coconut">Coconut</option> 
	<option value="mango">Mango</option> 
</select>

6.propTypes 属性约束 & 设置默认属性值

属性约束:

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Greeting.propTypes = {
  name: PropTypes.string
};

具体有哪些验证器:参考官网

属性默认值:

可以通过配置 defaultProps 为 props定义默认值:

class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

// 为属性指定默认值:
Greeting.defaultProps = {
  name: 'Stranger'
};

// 渲染 "Hello, Stranger":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);
提示:
    类型检查发生在 defaultProps 赋值之后,所以类型检查也会应用在 defaultProps 上面。

7.refs

Refs 提供了一种访问在 render 方法中创建的 DOM 节点或 React 元素的方式

何时使用 Refs
下面是几个适合使用 refs 的情况:
    处理焦点、文本选择或媒体控制。
    触发强制动画。
    集成第三方 DOM 库

如果可以通过声明式实现,则尽量避免使用 refs。
例如,不要在 Dialog 组件上直接暴露 open() 和 close() 方法,最好传递 isOpen 属性。

经典案例:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
  }

  focus() {
    // 直接使用原生 API 使 text 输入框获得焦点
    this.textInput.focus();
  }

  render() {
    // 使用 `ref` 的回调将 text 输入框的 DOM 节点存储到 React
    // 实例上(比如 this.textInput)
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focus}
        />
      </div>
    );
  }
}

React 组件在加载时将 DOM 元素传入 ref 的回调函数,在卸载时则会传入 nullref 回调会在componentDidMountcomponentDidUpdate 这些生命周期回调之前执行。

注意:
如果 ref 回调以内联函数的方式定义,在更新期间它会被调用两次,第一次参数是 null ,之后参数是 DOM 元素。这是因为在每次渲染中都会创建一个新的函数实例。
因此,React 需要清理旧的 ref 并且设置新的。通过将 ref 的回调函数定义成类的绑定函数的方式可以避免上述问题,但是大多数情况下无关紧要。

8.Fragments

React 中一个常见模式是为一个组件返回多个元素。Fragments 可以让你聚合一个子元素列表,并且不在DOM中增加额外节点

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

9.Error Boundaries错误边界

部分 UI 的异常不应该破坏了整个应用。为了解决 React 用户的这一问题,React 16 引入了一种称为 “错误边界” 的新概念。

如果一个类组件定义了一个名为 componentDidCatch(error, info): 的新方法,则其成为一个错误边界

错误边界无法捕获如下错误:
    1.事件处理 (了解更多)
    2.异步代码 (例如 setTimeout 或 requestAnimationFrame 回调函数)
    3.服务端渲染
    4.错误边界自身抛出来的错误 (而不是其子组件)        

经典案例

10.组件生命周期

图解

组件的生命周期可分成三个状态:
    Mounting:已插入真实 DOM
    Updating:正在被重新渲染
    Unmounting:已移出真实 DOM

生命周期的方法有:

componentWillMount在渲染前调用,在客户端也在服务端
componentDidMount在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)
componentWillReceiveProps在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用
shouldComponentUpdate返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用
componentDidUpdate在组件完成更新后立即调用。在初始化时不会被调用
componentWillUnmount在组件从 DOM 中移除的时候立刻被调用

forceUpdate:
component.forceUpdate(callback)
默认情况,当你的组件或状态发生改变,你的组件将会重渲。若你的render()方法依赖其他数据,你可以通过调用forceUpdate()来告诉React组件需要重渲。
调用forceUpdate()将会导致组件的 render()方法被调用,并忽略shouldComponentUpdate()。这将会触发每一个子组件的生命周期方法,涵盖,每个子组件的shouldComponentUpdate() 方法。若当标签改变,React仅会更新DOM。
通常你应该尝试避免所有forceUpdate() 的用法并仅在render()函数里从this.props和this.state读取数据。


11.ajax使用

React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。

当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: null,
      isLoaded: false,
      items: []
    };
  }

  componentDidMount() {
    fetch("https://api.example.com/items")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            isLoaded: true,
            items: result.items
          });
        },
        (error) => {
          this.setState({
            isLoaded: true,
            error
          });
        }
      )
  }

  render() {
    const { error, isLoaded, items } = this.state;
    if (error) {
      return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
      return <div>Loading...</div>;
    } else {
      return (
        <ul>
          {items.map(item => (
            <li key={item.name}>
              {item.name} {item.price}
            </li>
          ))}
        </ul>
      );
    }
  }
}

12.React UI库推荐

Element:一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库

https://eleme.github.io/element-react/#/zh-CN/quick-start 

 

Ant Desgin:一个服务于企业级产品的设计体系,基于『确定』和『自然』的设计价值观和模块化的解决方案,让设计者专注于更好的用户体验

https://ant.design/docs/react/introduce-cn 

 

UXCore:为企业后台而生

http://uxco.re/


13.react router  & react redux介绍

react router4.x :

官方文档:https://reacttraining.com/react-router/

官方文档提供了很多 examples ,文档也比较清楚,可以直接查看文档学习。

react redux:

官方文档:http://www.redux.org.cn/

核心思想:

  1.单一数据源:

    整个项目只有一个state树。

  2.state只读:

    只能通过触发action 修改state。

  3.使用纯函数执行修改:

    为了描述 action 如何改变 state tree ,你需要编写 reducers。

重要概念:

  Action:

    描述要干什么事情。准备需要的一些数据(一个简单对象)

 {
  type: ADD_TODO, text: 'Build my first Redux app' }

   Reducer:

    到底要怎么干。处理state,并返回新的state

function todoApp(state = initialState, action) {
	  switch (action.type) {
		case ADD_TODO:
		  return Object.assign({}, state, {
			todos: [
			  ...state.todos,
			  {
				text: action.text,
				completed: false
			  }
			]
		  })
		default:
		  return state
	  }
}

   Store:

  找到人正式干活。派发事件

store.dispatch(addTodo('Learn about actions'))

  展示组件:

    仅仅基于React,描述怎么展示,数据都从props里面获取

  容器组件:

    描述如何获取数据,状态更新,逻辑处理。基于react-redux

重要API:

 createStore:http://www.redux.org.cn/docs/api/createStore.html

 combineReducers:http://www.redux.org.cn/docs/api/combineReducers.html

   applyMiddleware:http://www.redux.org.cn/docs/api/applyMiddleware.html

react-redux文档 :http://www.redux.org.cn/docs/react-redux/api.html

综合案例参见官网TODOS:https://github.com/reduxjs/redux/tree/master/examples/todos

效果图:

 

14.拓展

react动画:

https://reactcommunity.org/react-transition-group/

react单元测试

React测试必须使用官方的测试工具库,但是它用起来不够方便,所以有人做了封装,推出了一些第三方库,其中Airbnb公司的Enzyme最容易上手。

官方也推荐使用  Enzyme 它在相同的功能上提供了一个更棒的高级 API。

Enzyme是官方测试工具库的封装,它模拟了jQuery的API,非常直观,易于使用和学习。

它提供三种测试方法:
        shallow
        render
        mount

 

 

推荐阅读:http://www.aliued.com/?p=4095

转载于:https://www.cnblogs.com/zcxgz/p/8615461.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值