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版本
存在多个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>
高,所以不要在同一个中同时使用这两个属性。
<Link>
- 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>
<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';