全局API
创建React组件
- 组件中必须(也有非必须的方案)有且只有一个根节点
1.函数式创建
- app.jsx
import React from 'react'
function App(props){
return (<div>我是app</div>)
}
复制代码
纯函数式创建的组件无声明周期,无state。适合无状态的组件使用。官方推荐。如果想使用状态,React在16.8增建了HOOKS
2.ES6类式创建
- app.jsx
import React from 'react'
class App extends React.component(){
constructor(props){
super(props)
this.state={
}
}
// 相关生命周期函数用不到的话可以省略
// ...
// 类式申明的组件必须要用render函数
render(){
return (<div></div>)
}
}
复制代码
3.采用React class创建
- app.jsx
var Hello = React.creatClass({
getDefaultProps: function(){
return {
name: 'pomy',
git: 'dwqs'
}
},
render: function(){
return (
<div>Hello,{this.props.name},git username is {this.props.dwqs}</div>
)
}
});
复制代码
生命周期
参考文档:React生命周期
getDefaultProps
对于每个组件实例来讲,这个方法只会调用一次,该组件类的所有后续应用,getDefaultPops 将不会再被调用,其返回的对象可以用于设置默认的 props(properties的缩写) 值。
注:返回的对象为this组件实例下的props
getInitialState
对于组件的每个实例来说,这个方法的调用有且只有一次,用来初始化每个实例的 state,在这个方法里,可以访问组件的 props。每一个React组件都有自己的 state,其与 props 的区别在于 state只存在组件的内部,props 在所有实例中共享
class App extends React.component(){
getInitialState() {
return {liked: false};
},
handleClick(event) {
this.setState({liked: !this.state.liked});
},
render() {
}
}
复制代码
访问的时候通过this.state访问
componentWillMount
该方法在首次渲染之前调用,也是再 render 方法调用之前修改 state 的最后一次机会。
componentDidMount
已经渲染出来了真实的DOM,这个时候可以访问DOM元素了。一般在此周期下进行服务端数据的请求
class App extends React.component(){
componentDidMount(){
console.log(this.getDOMNode())
}
render(){
return <div></div>
},
}
复制代码
componentWillReceiveProps
组件的 props 属性可以通过父组件来更改,这时,componentWillReceiveProps 将来被调用。可以在这个方法里更新 state,以触发 render 方法重新渲染组件。
class App extends React.component(){
componentWillReceiveProps(nextProps){
if(nextProps.checked !== undefined){
this.setState({
checked: nextProps.checked
})
}
}
render(){
return <div></div>
},
}
复制代码
shouldComponentUpdate
如果你确定组件的 props 或者 state 的改变不需要重新渲染,可以通过在这个方法里通过返回 false 来阻止组件的重新渲染,返回 `false 则不会执行 render 以及后面的 componentWillUpdate,componentDidUpdate 方法。
class App extends React.component(){
shouldComponentUpdate(){
return this.state.checked === nextState.checked;
//return false 则不更新组件
}
render(){
return <div></div>
},
}
复制代码
componentWillUpdate
这个方法和 componentWillMount 类似,在组件接收到了新的 props 或者 state 即将进行重新渲染前,componentWillUpdate(object nextProps, object nextState) 会被调用,注意不要在此方面里再去更新 props 或者 state
class App extends React.component(){
componentWillUpdate(){
}
render(){
return <div></div>
},
}
复制代码
componentDidUpdate
这个方法和 componentDidMount 类似,在组件重新被渲染之后,componentDidUpdate(object prevProps, object prevState) 会被调用。可以在这里访问并修改 DOM。
class App extends React.component(){
componentDidMount(){
}
render(){
return <div></div>
},
}
复制代码
componentWillUnmount
每当React使用完一个组件,这个组件必须从 DOM 中卸载后被销毁,此时 componentWillUnmout 会被执行,完成所有的清理和销毁工作,在 componentDidMount 中添加的任务都需要再该方法中撤销,如创建的定时器或事件监听器
class App extends React.component(){
componentWillUnmount(){
}
render(){
return <div></div>
},
}
复制代码
render
该方法会创建一个虚拟DOM,用来表示组件的输出。对于一个组件来讲,render方法是唯一一个必需的方法。render方法需要满足下面几点:
- 只能通过 this.props 和 this.state 访问数据(不能修改)
- 可以返回 null,false 或者任何React组件
- 只能出现一个顶级组件,不能返回一组元素
- 不能改变组件的状态
- 不能修改DOM的输出 render方法返回的结果并不是真正的DOM元素,而是一个虚拟的表现,类似于一个DOM tree的结构的对象。react之所以效率高,就是这个原因。
state的使用
react将状态存到state中,通过setState改变state中的值。从而出发dom渲染
注:但是不要直接修改state,要通过 this.setState 方法来修改。
// 利用函数设置
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
复制代码
或者
// 直接使用,注意在更改comment值后在下面不能直接拿到comment的新值,要取值的话可以采用回调的方式
this.setState({comment: 'Hello'});
this.setState({comment:'hello'},(nextState)=>{console.log(nextState.comment)})
复制代码
getDerivedStateFromProps
组件之间的传参
父子组件传参采用props
状态管理器 Redux
路由参数
jsx语法相关
标签类型
在JSX语法中,使用的标签类型有两种:DOM类型的标签(div、span等)和React组件类型的标签(关注后面文章)。DOM类型的标签需要标签的首字母小写,React组件类型的标签需要首字母大写。React也是通过首字母的大小写来判断渲染的是哪种类型的标签。
JSX语法
在{}中写入相关代码,jsx不支持if else ,支持三元运算符。
JSX添加style
<script type="text/babel">
var ok=1;
ReactDOM.render(
<div>
<p style={{
color:"red",
fontSize:50
}}>{ok==1?"我很帅":"我很有才华"}</p>
</div>,
document.querySelector("#wrap")
)
</script>
复制代码
JSX属性名
- 所有的属性都是驼峰命名的;
- class 属性 改为 className;
- for 属性 改为 htmlFor;
- colspan 属性 改为 colSpan
事件
onCLick
、onMouseOver
等
Redux
react-router
React.render((
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
{/* 当 url 为/时渲染 Dshboard */}
<IndexRoute component={Dashboard} />
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
), document.body)
复制代码
PropTypes 验证器
import React from 'react';
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// 利用属性做更多得事
}
}
MyComponent.propTypes = {
//你可以定义一个属性是特定的JS类型(Array,Boolean,Function,Number,Object,String,Symbol)。默认情况下,这些都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
//指定类型为:任何可以被渲染的元素,包括数字,字符串,react 元素,数组,fragment。
optionalNode: PropTypes.node,
// 指定类型为:一个react 元素
optionalElement: PropTypes.element,
//你可以类型为某个类的实例,这里使用JS的instanceOf操作符实现
optionalMessage: PropTypes.instanceOf(Message),
//指定枚举类型:你可以把属性限制在某些特定值之内
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 指定多个类型:你也可以把属性类型限制在某些指定的类型范围内
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 指定某个类型的数组
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 指定类型为对象,且对象属性值是特定的类型
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
//指定类型为对象,且可以规定哪些属性必须有,哪些属性可以没有
optionalObjectWithShape: PropTypes.shape({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired
}),
// 指定类型为对象,且可以指定对象的哪些属性必须有,哪些属性可以没有。如果出现没有定义的属性,会出现警告。
//下面的代码optionalObjectWithStrictShape的属性值为对象,但是对象的属性最多有两个,optionalProperty 和 requiredProperty。
//出现第三个属性,控制台出现警告。
optionalObjectWithStrictShape: PropTypes.exact({
optionalProperty: PropTypes.string,
requiredProperty: PropTypes.number.isRequired
}),
//加上isReqired限制,可以指定某个属性必须提供,如果没有出现警告。
requiredFunc: PropTypes.func.isRequired,
requiredAny: PropTypes.any.isRequired,
// 你也可以指定一个自定义的验证器。如果验证不通过,它应该返回Error对象,而不是`console.warn `或抛出错误。`oneOfType`中不起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
//你也可以提供一个自定义的验证器 arrayOf和objectOf。如果验证失败,它应该返回一个Error对象。
//验证器用来验证数组或对象的每个值。验证器的前两个参数是数组或对象本身,还有对应的key。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
复制代码
Fragments
对于一个组件中需要返回多个并列的节点的
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
复制代码
或者
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
复制代码
Refs
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
// 访问
const node = this.myRef.current;
render() {
return <div ref={this.myRef} />;
}
}
复制代码
或者采用回调的方式
function CustomTextInput(props) {
// 这里必须声明 textInput,这样 ref 回调才可以引用它
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>
);
}
复制代码
Context
可以用于跨父子组件传参
新的用法
1.创建一个context
- theme-context.js
export const themes = {
light: {
foreground: '#ffffff',
background: '#222222',
},
dark: {
foreground: '#000000',
background: '#eeeeee',
},
};
export const ThemeContext = React.createContext(
themes.dark // 默认值
);
复制代码
2.祖先组件
- app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
// 一个使用到ThemedButton组件的中间组件
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:state.theme === themes.dark? themes.light: themes.dark,
}));
};
}
render() {
// ThemedButton 位于 ThemeProvider 内
// 在外部使用时使用来自 state 里面的 theme
// 默认 dark theme
return (
<Page>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>
<Section>
<ThemedButton />
</Section>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
复制代码
3.子组件
import {ThemeContext} from './theme-context';
function ThemedButton(props) {
return (
<ThemeContext.Consumer>
{theme => (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
)}
</ThemeContext.Consumer>
);
}
export default ThemedButton;
复制代码
总结
祖先组件采用Provider包裹起来,子组件采用Consumers进行接收,每当Provider的值发生改变时, 作为Provider后代的所有Consumers都会重新渲染。 从Provider到其后代的Consumers传播不受shouldComponentUpdate方法的约束,因此即使祖先组件退出更新时,后代Consumer也会被更新。
之前的使用方式
1.在祖先组件中定义
- Form.js
export default class Form extends Component {
constructor(props) {
super(props);
this.state = {
}
}
// 传值
getChildContext(){
return {
component: this
};
}
render(){
return ()
}
}
// 声明类型
Form.childContextTypes = {
component: PropTypes.any
};
复制代码
在子组件中
- form-item.js
export default class FormItem extends Component {
constructor(props) {
super(props);
this.state = {
}
}
// 使用 this.context
parent(){
return this.context.component;
}
}
// 声明要就收的祖先组件的参数
FormItem.contextTypes = {
component: PropTypes.any
};
复制代码