1.生命周期
getDefaultProps 初始化Props 设置组件属性的默认值,通过组件的getDefaultProps方法
componentWillMount 在渲染前调用,在客户端也在服务端。
componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异部操作阻塞UI)。
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
可以在你确认不需要更新组件时使用。
componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
componentWillUnmount在组件从 DOM 中移除的时候立刻被调用。
2.绑定事件
【1】
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
【2】
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// This syntax ensures `this` is bound within handleClick
return (
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
);
}
}
【3】
class LoggingButton extends React.Component {
// This syntax ensures `this` is bound within handleClick.
// Warning: this is *experimental* syntax.
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
3.事件传递
react 16.8.6 以上:
<Button type={this.state.lighting.dl} onClick={this.lightingOperation("dl")}>
/**
* 开关操作
* @param {string} 灯光类型
*/
lightingOperation = type => e => {
console.log("开关操作", type, this.state.lighting[type]);
let cmd = "open";
if (this.state.lighting[type] == "primary") {
cmd = "close";
}
this._ws.send({ CMD: cmd, ROOMID: this.state.room, DEVID: "AllLamp" });
let lighting = { ...this.state.lighting };
lighting[type] = cmd == "open" ? "primary" : "";
this.setState({
lighting: lighting
})
}
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
class Popper extends React.Component{
constructor(){
super();
this.state = {name:'Hello world!'};
}
preventPop(name, e){ //事件对象e要放在最后
e.preventDefault();
alert(name);
}
render(){
return (
<div>
<p>hello</p>
{/* Pass params via bind() method. */}
<a href="https://reactjs.org" onClick={this.preventPop.bind(this,this.state.name)}>Click</a>
</div>
);
}
}
4.组件传值
【父】===》【子】(props)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
ES6
class Welcome extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
const element = <Welcome name="Sara1" />;
ReactDOM.render(
element,
document.getElementById('root')
);
【子】==》【父||兄】(状态提升)(类似vue中的$emit和$on)
const scaleNames = {
c: 'Celsius',
f: 'Fahrenheit'
};
function toCelsius(fahrenheit) {
return (fahrenheit - 32) * 5 / 9;
}
function toFahrenheit(celsius) {
return (celsius * 9 / 5) + 32;
}
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
render() {
const temperature = this.props.temperature;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={temperature}
onChange={this.handleChange} />
</fieldset>
);
}
}
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
this.state = {temperature: '', scale: 'c'};
}
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature});
}
handleFahrenheitChange(temperature) {
this.setState({scale: 'f', temperature});
}
render() {
const scale = this.state.scale;
const temperature = this.state.temperature;
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<TemperatureInput
scale="c"
temperature={celsius}
onTemperatureChange={this.handleCelsiusChange} />
<TemperatureInput
scale="f"
temperature={fahrenheit}
onTemperatureChange={this.handleFahrenheitChange} />
<BoilingVerdict
celsius={parseFloat(celsius)} />
</div>
);
}
}
ReactDOM.render(
<Calculator />,
document.getElementById('root')
);
以上关键:
onTemperatureChange={this.handleFahrenheitChange}
handleCelsiusChange(temperature) {
this.setState({scale: 'c', temperature});
}
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
5.react组合(类似vue中的slot)
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
//组件
class Layout extends React.Component {
render() {
console.log(this.props);
return (
<section>
<Link to="/home">{this.props.msg}</Link>
<div className="left">
{
this.props.children[0]
}
</div>
<div className="right">
{
this.props.children[1]
}
</div>
<Hfooter></Hfooter>
</section>
)
}
}
export default Layout;
class Home extends React.Component {
render() {
return (
<section>
<Layout msg="">
<div className="fv" key="left">hhhh</div>
<div className="fv" key="right">hhh3333h</div>
</Layout>
</section>
)
}
}
export default Home;
或者
class Home extends React.Component {
render() {
var leftHtml='<div className="fv" key="left">hhhh</div>';
return (
<section>
<Layout msg="" left={leftHtml}>
<div className="fv" key="left">hhhh</div>
<div className="fv" key="right">hhh3333h</div>
</Layout>
</section>
)
}
}
export default Home;
class Layout extends React.Component {
render() {
console.log(this.props);
return (
<section>
<Link to="/home">{this.props.msg}</Link>
<div dangerouslySetInnerHTML={{ __html: this.props.left }} />
<div className="left">
{
this.props.left
}
</div>
<div className="right">
{
this.props.children[1]
}
</div>
<Hfooter></Hfooter>
</section>
)
}
}
export default Layout;
【指定显示位置】
function SplitPane(props) {
return (
<div className="SplitPane">
<div className="SplitPane-left">
{props.left}
</div>
<div className="SplitPane-right">
{props.right}
</div>
</div>
);
}
function App() {
return (
<SplitPane
left={
<Contacts />
}
right={
<Chat />
} />
);
}
6.条件渲染 动态绑定
<div>
{showHeader && <Header />}
<Content />
</div>
条件渲染<Header />组件
6.1动态绑定属性
eg:动态绑定disable属性
<Button disabled={this.state.disabled} onClick={this.sendSms} type="primary">{state.btnTxt}</Button>
6.2 样式绑定 : https://blog.csdn.net/suwyer/article/details/81481507
/*这个方法名称是已经定义好的,不能改名称。用于定义初始状态*/
getInitialState:function(){
return {redorblue:this.props.defaultColor};
},
这个是使用react.createClass创建组件时使用的
20180719
jsx
1.只能有一个根节点,类似vue.
2.jsx中的注释
{}中可以写js代码
所有注释: {/**/}
3.在jsx中样式class要改成className 因为class是js中类的关键字,属于保留字。
eg:
<div className="title">11111</div>
4.行内样式
<div style={{fontSize:'30px',display:'block'}}>11111</div>
为什么要用两个大括号
第一个大括号是包裹,里面写js变量等
可以按下面的理解
var s={
fontSize:'30px',
display:'block'
}
<div style={s}>11111</div>
5.事件
见上方
6.循环渲染
class Hello extends React.Component {
render(){
var arr=[1,2,3,4,5,6,7]
return{
<div>
{
arr.map((v,i)=>{
return <p key={i}>{v}</p>
})
}
</div>
}
}
}
以上使用map不可使用forEach,因为map可以有返回值,forEach没有返回值
react和vue 循环时的key是为了下次渲染时加快效率,可以按数据库索引来理解
循环内嵌条件渲染
<div style={{ flex: '7', marginLeft: "13%" }}>
{
Object.keys(this.state.roomObj).map((key) => {
return (
<div key={key}>
<List
rowKey={key}
grid={{
gutter: 0,
xl: 10,
lg: 5,
md: 5,
sm: 5,
xs: 5,
}}
loading={loading}
dataSource={this.state.roomObj[key]}
renderItem={item => (
<List.Item key={item.roomid} className={styles.resetListItemMargin}>
<Card
onClick={this.roomInfo(item.roomid)}
hoverable
size="small"
className={item.member > 0 ? styles.resetMarginColor : styles.resetMargin}
actions={[
<Tooltip key="member" title="人数" >
<IconFont className={styles.resetFont} type="icon-renshu" style={{ color: item.member > 0 ? '#1890ff' : 'grey' }} />
</Tooltip>,
<Tooltip key="light" title="灯光">
<IconFont className={styles.resetFont} type="icon-dengguang" style={{ color: item.light === true ? '#1890ff' : 'grey' }} />
</Tooltip>,
<Tooltip key="airConditioner" title="空调" >
<IconFont className={styles.resetFont} type="icon-kongtiao" style={{ color: item.airConditioner === true ? '#1890ff' : 'grey' }} />
</Tooltip>,
<Tooltip key="curtain" title="窗帘">
<IconFont className={styles.resetFont} type="icon-chuanglian" style={{ color: item.curtain === true ? '#1890ff' : 'grey' }} />
</Tooltip>
]}
>
<div className={styles.cardItemContent}>
<CardInfo
roomid={item.roomid}
temperature={item.temperature}
sos={item.sos === true ? 'red' : 'grey'}
/>
</div>
</Card>
</List.Item>
)}
/>
{
key == Object.getOwnPropertyNames(this.state.roomObj).length || <hr />
}
</div>
)
})
}
</div>
7.代码分离
9数据传递
使用组件时传递参数:
import Header from '../compentes/Header'
class Hello extends React.Component {
render(){
var arr=[1,2,3,4,5,6,7];
var obj={a:1234,b:"你好"}
return{
<div>
<Header title="this is header" mHeader={obj} ></Header>
{
arr.map((v,i)>{
return <p key={i}>{v}</p>
})
}
</div>
}
}
}
//组件
class Header extends React.Component {
render(){
return{
<div>
<p>{this.props.title}</p>
<p>{this.props.mHeader.a}</p>
</div>
}
}
}
export default Header;
10.区别开发环境和生产环境
if(_DEV_){
//开发环境下执行
}
11类似vue中的router-view,做布局页
class App extends React.Component {
render(){
return{
<div>
<div>header自定义头部</div>
<P>{this.pprops.children}</p>
<div>footer自定义底部</div>
</div>
}
}
}
export default App
12.路由配置文件
<Route path="/loginPass/:phone?" component={asyncLoad(() => import('../views/login/loginPass'), "")} />
类似vue 在path中加参数时有?的话,就表示:后面的值不是必须的,可以为空
13es6条件渲染
class Hheader extends React.Component {
render() {
return (
<div className="Hheader">
{
this.props.header.lTxt ? <div className="left" onClick={this.goBack.bind(this)}>{this.props.header.lTxt}</div> : ""
}
<div className="center">{this.props.header.title}</div>
<div className="right">{this.props.header.rTxt}</div>
</div>
)
}
goBack(){
}
}
export default Hheader;
14.自定义组件样式设置
//组件
class Hscroll extends React.Component{
render(){
console.log(this.props)
return(
<div className={this.props.className}>
{
this.props.children
}
</div>
)
}
}
<Hscroll className="has-header has-footer">
</Hscroll>
class Hscroll extends React.Component{
render(){
console.log(this.props)
return(
<div className={this.props.className.join(" ")}>
{
this.props.children
}
</div>
)
}
}
<Hscroll className={['has-header','has-footer']}>
</Hscroll>
15.引入ant-mobile
安装依赖
npm install antd-mobile --save
入口文件引用样式文件
//引入and-mobile 样式
import 'antd-mobile/dist/antd-mobile.css';
局部组件使用
import { Button, List, InputItem, WhiteSpace } from 'antd-mobile';
未解决问题:按需加载
16.使用getFieldProps
import React from 'react';
import ReactDOM from 'react-dom';
import '../../assets/css/basic.scss';
import './login.scss';
//组件
import Hheader from '../../components/hheader/index';
import Hscroll from '../../components/hscroll/index';
import { Button, List, InputItem, WhiteSpace } from 'antd-mobile';
import { createForm } from 'rc-form';
class Login extends React.Component {
render() {
const { getFieldProps } = this.props.form;
return (
<div className="login">
<Hheader header={{ title: "登录", lTxt: "返回", url: '/home' }} />
<Hscroll className="has-header has-footer">
<img className="login_logo" src="/img/login_logo.png" alt="" />
<List renderHeader={() => ''} className="login-input">
<InputItem {...getFieldProps('phone')} type="phone"><i className="iconfont icon-shouji1"></i></InputItem>
</List>
<Button type="primary" className="login-btn">登录</Button>
</Hscroll>
</div>
)
}
}
const LoginForm = createForm()(Login);//重要,否则会报找不到getFieldProps
export default LoginForm;
或者
export default createForm()(Login);
17.获取使用getFieldProps用户输入的值,input取值
let userInfo = this.props.form.getFieldsValue();
console.log(userInfo);
----{phone:15757801424}
17.1 普通非受控组件取值
我们推荐使用 受控组件 来实现表单。 在受控组件中,表单数据由 React 组件处理。如果让表单数据由 DOM 处理时,替代方案为使用非受控组件。
受控组件和非受控组件的区别就是数据是否由react处理,非受控组件的数据通过ref用DOM来处理
import React , {Component} from 'react';
export default class App extends Component{
search(){
const inpVal = this.input.value;
console.log(inpVal);
}
render(){
return(
<div>
<input type="text" ref={input => this.input = input} defaultValue="Hello"/>
<button onClick={this.search.bind(this)}></button>
</div>
)
}
}
---------------------
本文来自 Pinkh 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/Shuiercc/article/details/81383679?utm_source=copy
使用defaultValue表示组件的默认状态,此时它只会被渲染一次,后续的渲染不起作用;input的值不随外部的改变而改变,由自己状态改变。
zjeg:
handleOk(e) {
console.log( this.input.refs.input.value);
this.setState({
code:this.input.refs.input.value
});
},
<Modal className="hModal"
title="请输入验证码"
visible={this.state.visible}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<br />
<Row>
<Col span={18}> <Input ref={(input) => this.input = input} placeholder="请输入验证码" /></Col>
<Col span={5} offset={1}> <Button disabled={state.disabled} onClick={this.sendSms} type="primary">{state.btnTxt}</Button></Col>
</Row>
<br />
</Modal>
17.2 受控组件
import React , {Component} from 'react';
export default class App extends Component{
constructor(props){
super(props);
this.state = {
inpValu:''
}
}
handelChange(e){
this.setState({
inpValu:e.target.value
})
}
render(){
return(
<div>
<input type="text" onChange={this.handelChange.bind(this)} defaultValue={this.state.inpValu}/>
</div>
)
}
}
input 输入框的值会随着用户输入的改变而改变,onChange通过对象e拿到改变之后的状态并更新state,setState根据新的状态触发视图渲染,完成更新。
使用form取值
import React from 'react'
import {
Form,
Row,
Select,
Input,
Col
} from 'antd';
const createForm = Form.create;
const FormItem = Form.Item;
let ExceptionBehaviorlist = React.createClass({
render() {
const {
getFieldProps
} = this.props.form;
return(
<Modal ref="hmodal" title="确认操作" maskClosable={false} destroyOnClose={true} onCancel={this.hideModal} onOk={this.handleOk} visible={state.visible} width="520" >
<Form horizontal>
<Row>
<Col span="24">
<FormItem label="状态:">
<Select {...getFieldProps('state')} defaultValue="" style={{ width: 480 }}>
<Option value="20">正常</Option>
<Option value="30">异常</Option>
</Select>
</FormItem>
</Col>
</Row>
<Row>
<FormItem label="备注">
<textarea {...getFieldProps('remark', { initialValue: '' })} style={{ width: 480, height: 100 }}>
</textarea>
{/* <Input {...getFieldProps('remark', { initialValue: '' })} style={{ width: 420, height: 100 }} /> */}
</FormItem>
</Row>
</Form>
</Modal>
)
}
})
取值:
handleOk() {
var params = this.props.form.getFieldsValue();
},
赋值:
this.props.form.setFieldsValue({
state: record.state,
remark: record.remark
})
18.路由js跳转和参数传递
1.普通跳转
this.props.history.push({ pathname:'/loginPass'});
19.某些配置的react不会自动更新
目录太深,改浅一点就好了
*******************************************************************************************************************************
使用 ant design
1.创建表单
import {Form,Row,Col,Select,Input} from 'antd';
const createForm = Form.create;
const FormItem = Form.Item;
var AdjustRecord = React.createClass({
render() {
const { getFieldProps, getFieldValue } = me.props.form;
return (
<Form form={this.props.form}>
<Row>
<FormItem {...formItemLayout} label="状态:">
<Select defaultValue="1" style={{ width: 120 }} onChange={this.handleChange}>
<Option value="1">同意</Option>
<Option value="2">拒绝</Option>
</Select>
</FormItem>
</Row>
{state.value != 2 ? "" :
<Row><FormItem {...formItemLayout} label="备注:">
<Input placeholder="请输入拒绝备注" {...getFieldProps('reason', { rules: [{ required: true, message: '必填' }] })} />
</FormItem>
</Row>
}
</Form>
</div>
);
}
AdjustRecord = createForm()(AdjustRecord);
export default AdjustRecord
20.pc端 页面滚动加载,瀑布式,页面上拉加载更多
npm install react-infinite-scroller
<InfiniteScroll
initialLoad={false}
// pageStart={0}
loadMore={this.handleInfiniteOnLoad}
hasMore={state.hasMore&&!state.loading}
useWindow={false}>
<Table columns={columns2} rowKey={this.rowKey}
dataSource={this.state.dataTrade}
pagination={false} />
</InfiniteScroll>
//加载更多
handleInfiniteOnLoad() {
let me = this;
let current = me.state.current;
if (current > this.state.totalPage) {
console.log(current, "<><我是有底线的><>", this.state.totalPage);
message.info("我是有底线的");
return;
}
me.setState({
current: current + 1
}, () => {
me.pagefetch({
current: me.state.current,
pageSize: me.state.pageSize
});
})
},