React笔记(二) 受控/非受控组件 React-Router

147 阅读4分钟

key

key 可以帮助 React 识别哪些元素改变了,比如被添加或删除。数组中的每一个元素都需要设定key值,否则会报错。

NumberList组件接收 numbers 数组作为参数并输出一个元素列表。

const numbers = [1, 2, 3, 4, 5];
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>  
  <li>{number}</li>);  // × 没加key会报错
  <li key={number.toString()}>//在 map() 方法中的元素需要设置 key 属性。
  
  return (
    <ul>{listItems}</ul>  );
}

  
ReactDOM.render(
  <NumberList numbers={numbers} />,  document.getElementById('root')
);

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

key 会传递信息给 React ,但不会传递给组件。如果组件中需要使用 key 属性的值,请用其他属性名显式传递这个值:

const content = posts.map((post) =>
  <Post
    key={post.id}    id={post.id}    title={post.title} />
);

上面例子中,Post 组件可以读出 props.id,但是不能读出 props.key。

表单受控组件

表单受控组件:

由React控制表单输入内容和用户输入过程的组件。

  1. 设置value值,value由state控制
  2. value值一般在onChange事件中通过setState进行修改 表单非受控组件:

表单由 DOM 处理的组件

  1. 不设置value值
  2. 通过ref获取dom节点然后再取value值

Refs&DOM

从组件获取真实 DOM 的节点


    var MyComponent = React.createClass({
      handleClick: function() {
        this.refs.myTextInput.focus();
      },
      render: function() {
        return (
          <div>
            <input type="text" ref="myTextInput" />
            <input type="button" value="Focus the text input" onClick={this.handleClick} />
          </div>
        );
      }
    });

    ReactDOM.render(
      <MyComponent />,
      document.getElementById('example')
    );

上面代码中,组件 MyComponent 的子节点有一个文本输入框,用于获取用户的输入。这时就必须获取真实的 DOM 节点,虚拟 DOM 是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的 DOM 节点。

需要注意的是,由于 this.refs.[refName] 属性获取的是真实 DOM ,所以必须等到虚拟 DOM 插入文档以后,才能使用这个属性,否则会报错。上面代码中,通过为组件指定 Click 事件的回调函数,确保了只有等到真实 DOM 发生 Click 事件之后,才会读取 this.refs.[refName] 属性。

表单非受控组件

用户在表单填入的内容,属于用户跟组件的互动,所以不能用 this.props读取


    var Input = React.createClass({
      getInitialState: function() {
        return {value: 'Hello!'};
      },
      handleChange: function(event) {
        this.setState({value: event.target.value});
      },
      render: function () {
        var value = this.state.value;
        return (
          <div>
            <input type="text" value={value} onChange={this.handleChange} />
            <p>{value}</p>
          </div>
        );
      }
    });

    ReactDOM.render(<Input/>, document.body);

上面代码中,文本输入框的值,不能用 this.props.value 读取,而要定义一个 onChange 事件的回调函数,通过 event.target.value 读取用户输入的值。textarea 元素、select元素、radio元素都属于这种情况

Router

react-router 是官方指定和维护的 React 路由库,它通过管理 URL,实现组件间切换和状态 (state) 的变化。Router组件本身只是一个容器,真正的路由要通过Route组件定义。

传统开发中的路由,是由服务端根据不同的用户请求地址 URL,返回不同内容的页面,而前端路由则将这些任务通过 JS 在浏览器端完成,SPA 应用(单页面应用) 则是前端路由的最佳适用场景,因为它结构简单,只需更新页面部分显示内容 也不必每次都从服务端获取内容。

基本用法

// 使用 ES6 的转译器,如 babel
import { Router, Route, Link } from 'react-router'

// 不使用 ES6 的转译器
var ReactRouter = require('react-router')
var Router = ReactRouter.Router
var Route = ReactRouter.Route
var Link = ReactRouter.Link

Router 组件

react-router 的工作方式,是在组件树顶层放一个 Router 组件,然后在组件树中散落着很多 Route 组件,顶层的 Router 组件负责分析监听 URL 的变化,在它之下的 Route 组件可以直接读取这些信息。

Router 是“提供者”,Route是“消费者”。

BrowserRouter:使用于现代浏览器,支持H5 history

APIHashRouter:常用于旧款浏览器。

MemoryHistory:常用于非DOM环境,例如React Native或者测试,History存于内存。

BrowserRouter 方式的路由:

https://xxx.com/a
https://xxx.com/b

HashRouter 方式的路由:

https://xxx.com/#/a
https://xxx.com/#/b

createMemoryHistory 
主要用于服务器渲染。它创建一个内存中的history对象,不与浏览器URL互动

引入方式:

import {Route, BrowserRouter as Router} from "react-router-dom";

对于浏览器项目通常选用: <BrowserRouter><HashRouter> 组件来实现 Router

react-native 项目通常选用:<MemoryHistory>

Route 组件

Route只是一个具有渲染方法的普通 React 组件,路由匹配成功则渲染该组件。

三个常用属性:

path:路由的匹配规则(可以省略)path可以表示相对路径,也可以表示绝对路径,一般多采用绝对路径.

exact:用于精确匹配路由(可以省略)

component:需要渲染的组件

一个完整的路由:

import {Route, BrowserRouter as Router} from "react-router-dom";
import A from 'A'
import B from 'B'
const routing = (
    <Router>
       <Route component={Home} >
       <Route exact path="/a" component={A} />
       <Route exact path="/b" component={B} />
    </Router>
)

ReactDOM.render(routing, document.getElementById("root"));

路由跳转

Link组件 生成一个链接,允许用户点击后跳转到另一个路由

import React, {Component} from "react";
import {Link} from 'react-router';
class App extends Component {
    render() {
        return (
            <div>
                <h1>App</h1>
                <ul>
                    <li><Link to="/about">About</Link></li>
                    <li><Link to="/inbox">Inbox</Link></li>
                </ul>
                {this.props.children}
            </div>
        )
    }
}

Link组件用于正常的用户点击跳转,browserHistory.push则用来处理表单跳转、点击按钮跳转等操作。

class Inbox extends Component {
    Logout(){
        browserHistory.push('/');    //该方法可用于表单跳转和点击按钮跳转
    }

    render() {
        return (
            <div>
                <h2>Inbox</h2>
                {this.props.children || "Welcome to your Inbox"}
                <ul>
                    <li><Link to="/">App</Link></li>
                    <li><Link to="/inbox/message">Message</Link></li>
                </ul>
                {this.props.children}
                <button onClick={this.Logout.bind(this)}>退出</button>
            </div>
        )
    }
}

参考文章:

react-guide.github.io/react-route…

www.ruanyifeng.com/blog/2015/0…

zhuanlan.zhihu.com/p/78176856

www.jianshu.com/p/5e8297858…