React开发环境安装配置和基础入门

React基础入门

ReactDOM.render()

将指定的模板或节点内容插入指定的节点(通常是一个div)

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('example')
);

以上表示,将一个h1标签插入一个id为“example”的div节点内

<head>
  <link rel="stylesheet" href="./src/css/style.css"/>
</head>
<div id="example"></div>
<script src="./src/bundle.js"></script>

运行结果是

<head>
  <link rel="stylesheet" href="./src/css/style.css"/>
</head>
<div id="example">hello, world</div>
<script src="./src/bundle.js"></script>

JSX

本质是语法糖,经过编译后最终生成的是js代码
特点是支持类xml语法并且支持与js代码混写

var names = ['Alice', 'Emily', 'Kate'];

ReactDOM.render(
  <div>
  {
    names.map(function (name) {
      return <div>Hello, {name}!</div>
    })
  }
  </div>,
  document.getElementById('example')
);

尖括号<>内容属于jsx语法内容;大括号{}内容属于js代码内容
如果jsx内包含一个js数组对象变量,将自动调用其遍历器获取其全部成员

var arry = ["hello","world"];
<ul>
  {arr.map(item => (
  <li>{item+"zph"}</li>
  ))}
</ul>

另一个例子

class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}

//等同于
return React.createElement('div', {className: 'shopping-list'},
  React.createElement('h1', /* ... h1 children ... */),
  React.createElement('ul', /* ... ul children ... */)
);
// Example usage: <ShoppingList name="Mark" />

组件

组件本质是一个包含render方法的对象(类)。每次使用组件将生成一个新的对象实例

var MyComponent = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

ReactDOM.render(
  <MyComponent name="John" />,
  document.getElementById('example')
);

es6的module形式,向外暴露一个class类

export default class MyComponent extends React.Component{
  constructor(){
    super();    
  }
  render(){
    return(
      <h1>Hello {this.props.name}</h1>;
    );
  }
}

js保留字问题:
class使用 className代替
for 使用htmlFor代替

this.props.children

  • 如果当前组件没有子节点 返回值是 undefined
  • 如果只有一个子节点,返回值数据类型是 object
  • 如果有多个子节点,返回值数据类型就是 array
var NotesList = React.createClass({
  render: function() {
    return (
      <ol>
      {
        React.Children.map(this.props.children, function (child) {
          return <li>{child}</li>;
        })
      }
      </ol>
    );
  }
});

ReactDOM.render(
  <NotesList>
    <span>hello</span>
    <span>world</span>
  </NotesList>,
  document.body
);

PropTypes类型检查

React v15.5版本之后React.PropTypes使用方式已经移除,可使用 prop-types库来代替

import PropTypes from 'prop-types';

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

Greeting.propTypes = {
  name: PropTypes.string
};
//本质是指定一个名为propTypes的静态属性,也可在类中使用static关键字的形式使用

一些基本类型的检查

  optionalArray: PropTypes.array,
  optionalBool: PropTypes.bool,
  optionalFunc: PropTypes.func,
  optionalNumber: PropTypes.number,
  optionalObject: PropTypes.object,
  optionalString: PropTypes.string,
  optionalSymbol: PropTypes.symbol,

// Anything that can be rendered: numbers, strings, elements or an array
  // (or fragment) containing these types.
  optionalNode: PropTypes.node,

  // A React element.
  optionalElement: PropTypes.element,

  // You can also declare that a prop is an instance of a class. This uses
  // JS's instanceof operator.
  optionalMessage: PropTypes.instanceOf(Message),

  // You can ensure that your prop is limited to specific values by treating
  // it as an enum.
  optionalEnum: PropTypes.oneOf(['News', 'Photos']),

  // An object that could be one of many types
  optionalUnion: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Message)
  ]),

  // An array of a certain type
  optionalArrayOf: PropTypes.arrayOf(PropTypes.number),

  // An object with property values of a certain type
  optionalObjectOf: PropTypes.objectOf(PropTypes.number),

  // An object taking on a particular shape
  optionalObjectWithShape: PropTypes.shape({
    color: PropTypes.string,
    fontSize: PropTypes.number
  }),

  // You can chain any of the above with `isRequired` to make sure a warning
  // is shown if the prop isn't provided.
  requiredFunc: PropTypes.func.isRequired,

  // A value of any data type
  requiredAny: PropTypes.any.isRequired,

以上是指定类型,如果需要指定是不可缺省,可在后面追加isRequired,如
optionalArray: PropTypes.array.isRequeired 更详细的可参考官方文档内容

defaultProps 设置默认值

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

// Specifies the default values for props:
Greeting.defaultProps = {
  name: 'Stranger'
};

// Renders "Hello, Stranger":
ReactDOM.render(
  <Greeting />,
  document.getElementById('example')
);

Refs

直接获取真实的DOM节点而非virtural DOM
使用场景:获取焦点、触发动画、集成第三方DOM库等
组件标签内使用ref关键字定义一个callback回调,此回调将在组件加载或卸载完成后立即执行。回调函数参数是dom节点,如

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

  focusTextInput() {
    // Explicitly focus the text input using the raw DOM API
    this.textInput.focus();
  }

  render() {
    // Use the `ref` callback to store a reference to the text input DOM
    // element in an instance field (for example, this.textInput).
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

方法组件中使用ref

function CustomTextInput(props) {
  // textInput must be declared here so the ref callback can refer to it
  let textInput = null;

  function handleClick() {
    textInput.focus();
  }

  return (
    <div>
      <input
        type="text"
        ref={(input) => { textInput = input; }} />
      <input
        type="button"
        value="Focus the text input"
        onClick={handleClick}
      />
    </div>
  );  
}

避免使用String Refs 如,this.refs.textInput 此种使用方式以后将会被废弃

this.state

  • state被更新后将重新调用组件的render方法
  • 作用域只针对当前的组件不会污染其他组件
  • 初始化state操作可放置于constructor构造函数中
  • 调用setState({key:value})修改state

this.props

用于给获取传给当前组件的数据 如 <component key=value/> 给当前组件传递了key:value数据,当前组件可使用this.props.key 获取value值

传递当前全部的props到子组件

<component {...this.props}/>

子组件更新父组件内容

通过给子组件传函数

react-mixin

公用功能或代码

生命周期

React router

以下内容基于react-router 4.x版本

Route Tester

参考文档

存在多个Repository:
* react-router: React Router 提供核心的路由组件与函数
* react-router-dom: 用于 DOM 绑定的 React Router
* react-router-native: 用于 React Native 的 React Router
* react-router-redux: React Router 和 Redux 的集成
* react-router-config: 静态路由配置帮助助手

web网站应用只需安装react-router-dom

react-router-dom暴露出react-router中暴露的对象与方法,因此只需安装并引用react-router-dom即可,react-router-dom比react-router多了<Link>、 <BrowserRouter>

$ npm install --save react-router-dom

对于网页项目,存在<BrowserRouter><HashRouter>两种组件

区别:

?每个路由器都会创建一个history对象并用其保持追踪当前location并且在有变化时对网站进行重新渲染

<Router/>

Router组件的children可以放任内容(组件或普通标签),但只可有唯一的子元素
如,

<Router>
    <div>
      <ul>
        <li><Link to="/">首页</Link></li>
        <li><Link to="/about">关于</Link></li>
        <li><Link to="/topics">主题列表</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>

Router是所有路由组件共用的底层接口,一般我们的应用并不会使用这个接口,而是使用高级的路由:

  • <BrowserRouter>:使用 HTML5 提供的 history API 来保持 UI 和 URL 的同步;
  • <HashRouter>:使用 URL 的 hash (例如:window.location.hash) 来保持 UI 和 URL 的同步;
  • <MemoryRouter>:能在内存保存你 “URL” 的历史纪录(并没有对地址栏读写);
  • <NativeRouter>:为使用React Native提供路由支持;
  • <StaticRouter>:从不会改变地址;

<Route/>

当一个location匹配Route的path时,渲染某些UI内容

<Router>
  <div>
    <Route exact path="/" component={Home}/>
    <Route path="/news" component={NewsFeed}/>
  </div>
</Router>

Route的一些属性:
* path(string): 路由匹配路径。(没有path属性的Route 总是会 匹配);
* exact(bool):为true时,则要求路径与location.pathname必须完全匹配;
* strict(bool):true的时候,有结尾斜线的路径只能匹配有斜线的location.pathname

Route的三种不同的渲染内容的方式:
<Route component><Route render><Route render>

<Route component>的优先级要比<Route render>高,所以不要在同一个中同时使用这两个属性。

  • to(string/object):要跳转的路径或地址;
  • replace(bool):为 true 时,点击链接后将使用新地址替换掉访问历史记录里面的原地址;为 false 时,点击链接后将在原有访问历史记录的基础上添加一个新的纪录。默认为 false;
// to为string
<Link to="/about">关于</Link>

// to为obj
<Link to={{
  pathname: '/courses',
  search: '?sort=name',
  hash: '#the-hash',
  state: { fromDashboard: true }
}}/>

// replace
<Link to="/courses" replace />

<NavLink><Link>的一个特定版本, 会在匹配上当前 URL 的时候会给已经渲染的元素添加样式参数,组件属性:

  • activeClassName(string):设置选中样式,默认值为 active;
  • activeStyle(object):当元素被选中时, 为此元素添加样式;
  • exact(bool):为 true 时, 只有当地址完全匹配 class 和 style 才会应用;
  • strict(bool):为 true 时,在确定位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线;
  • isActive(func):判断链接是否激活的额外逻辑的功能;
// activeClassName选中时样式为selected
<NavLink
  to="/faq"
  activeClassName="selected"
>FAQs</NavLink>

// 选中时样式为activeStyle的样式设置
<NavLink
  to="/faq"
  activeStyle={{
    fontWeight: 'bold',
    color: 'red'
   }}
>FAQs</NavLink>

// 当event id为奇数的时候,激活链接
const oddEvent = (match, location) => {
  if (!match) {
    return false
  }
  const eventID = parseInt(match.params.eventID)
  return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink
  to="/events/123"
  isActive={oddEvent}
>Event 123</NavLink>

<Switch/>

该组件用来渲染匹配地址的第一个<Route>或者<Redirect>

思考如下内容:

<Router>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Router>

如果现在的URL是/about,那么<About>, <User>,<NoMatch>都会被渲染,因为它们都与路径(path)匹配。这种设计,允许我们以多种方式将多个组合到我们的应用程序中,例如侧栏(sidebars),面包屑(breadcrumbs),bootstrap tabs等等。

然而,偶尔我们只想选择一个来渲染。如果我们现在处于/about,我们也不希望匹配/:user(或者显示我们的 “404” 页面 )。此时需要 Switch 的方法来实现:

<Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/about" component={About}/>
  <Route path="/:user" component={User}/>
  <Route component={NoMatch}/>
</Switch>

现在,如果我们处于/about,<Switch>将开始寻找匹配的<Route><Route path="/about"/> 将被匹配, <Switch>将停止寻找匹配并渲染<About>。同样,如果我们处于/michael,<User>将被渲染。

react样式使用

内联样式写法

import React from 'react';
export default class ComponentHeader extends React.Component {

constructor(){
    super();
    this.state ={
        miniHeader: false //默认加载的时候还是高(不是 mini)的头部
    };
};

  switchHeader(){
    this.setState({
        miniHeader: !this.state.miniHeader
    });
  };

    render() {
        const styleComponentHeader = {
            header: {
                backgroundColor: "#333333",
                color: "#FFFFFF",
                "padding-top": (this.state.miniHeader) ? "3px" : "15px",
                paddingBottom: (this.state.miniHeader) ? "3px" : "15px"
            },
            //还可以定义其他的样式
        };
        return (
            <header style={styleComponentHeader.header} className="smallFontSize"
            onClick={this.switchHeader.bind(this)}>
                <h1>这里是头部</h1>
            </header>
        )
    }
}

引用样式表形式

通过import css文件的方式,组件可使用className引用样式

css模块化

要解决的问题:
- 全局污染
- 命名混乱

需要安装以下modules:
css-loader style-loader

可选的 babel-plugin-react-attrs 用于解决className,htmlFor等名称冲突问题

配置webpack.config

在webpack.config.js文件loaders节点添加以下内容即可
下面是添加的 css 的 loader,也即是 css 模块化的配置

{
  test: /\.css$/,
  loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
}

导入css
var footerCss = require("../../footer.css")
使用css
<footer className = {footerCss.miniFooter}/>

全局样式:在css文件中定义中使用global显式指定此样式将作为全局样式使用。默认样式是loacal无需显式
:local(.myclass)(color:red)
:global(.btn)(color:green)

JSX样式和css互转

CSS into the React in-line style

Ant Design

类比另一个UI框架:material-UI
Ant Design 官网

Antd使用方式:

下面是使用 ant-design 的webpack.config配置文件需要修改的loaders节点内容
{ test: /\.css$/, loader: 'style-loader!css-loader' }
主页引入样式
import 'antd/dist/antd.css'
组件中引入需要的控件
import { Input } from 'antd';

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值