cnpm i create-react-app -g
create-react-app react2019
cd react2019
yarn start
react.js
是 React 的核心库react-dom.js
是提供与DOM相关的功能,内部比较重要的方法是render,它用来向浏览器里插入DOM元素createElement
语法,以下代码等价ReactDOM.render(
<h1>Hello</h1>,
document.getElementById('root')
);
<h1 className="title" style={{color:'red'}}>hello</h1>
React.createElement("h1", {
className: "title",
style: {
color: 'red'
}
}, "hello");
createElement的结果
{
type:'h1',
props:{
className: "title",
style: {
color: 'red'
}
},
children:"hello"
}
let title = 'hello';
ReactDOM.render(
<h1>{title}</h1>,
document.getElementById('root')
);
ReactDOM.render(
<h1 className="title" style={{color:'red'}}>Hello</h1>,
document.getElementById('root')
);
if
或者 for
语句里使用JSX
if中使用
import React from 'react';
import ReactDOM from 'react-dom';
function greeting(name) {
if (name) {
return <h1>Hello, {name}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
let name = 'zhufeng';
const element = greeting(name);
ReactDOM.render(
element,
document.getElementById('root')
);
for中使用
import React from 'react';
import ReactDOM from 'react-dom';
let names = ['张三','李四','王五'];
let elements = [];
for(let i=0;i<names.length;i++){
elements.push(<li>{names[i]}</li>);
}
ReactDOM.render(
<ul>
{elements}
</ul>,
document.getElementById('root')
);
immutable
不可变的。当元素被创建之后,你是无法改变其内容或属性的。一个元素就好像是动画里的一帧,它代表应用界面在某一时间点的样子ReactDOM.render()
方法import React from 'react';
import ReactDOM from 'react-dom';
function tick() {
const element = (
<div>
{new Date().toLocaleTimeString()}
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
props
对象并返回了一个React元素function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
props
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="zhufengjiagou" />;
ReactDOM.render(
element,
document.getElementById('root')
);
class Panel extends Component{
render(){
let {header,body} = this.props;
return (
<div className="container">
<div className="panel-default panel">
<Header header={header}></Header>
<Body body={body}/>
</div>
</div>
)
}
}
class Body extends Component{
render(){return (<div className="panel-body">{this.props.body}</div>)}
}
class Header extends Component{
render(){return (<div className="panel-heading">{this.props.header}</div>)}
}
let data = {header:'zhufeng',body:'jiagou'};
ReactDOM.render(<Panel {...data}/>,window.root);
props
纯函数
没有改变它自己的输入值,当传入的值相同时,总是会返回相同的结果//纯函数
function sum(a, b) {
return a + b;
}
//非纯函数
function withdraw(account, amount) {
account.total -= amount;
}
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
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({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
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.'
);
}
})
};
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Person extends React.Component{
static defaultProps = {
name:'Stranger'
}
static propTypes={
name: PropTypes.string.isRequired,
age: PropTypes.number.isRequired,
gender: PropTypes.oneOf(['male','famale']),
hobby: PropTypes.array,
postion: PropTypes.shape({
x: PropTypes.number,
y:PropTypes.number
}),
age(props,propName,componentName) {
let age=props[propName];
if (age <0 || age>120) {
return new Error(`Invalid Prop ${propName} supplied to ${componentName}`)
}
}
}
render() {
let {name,age,gender,hobby,position}=this.props;
return (
<table>
<thead>
<tr>
<td>姓名</td>
<td>年龄</td>
<td>性别</td>
<td>爱好</td>
<td>位置</td>
</tr>
</thead>
<tbody>
<tr>
<td>{name}</td>
<td>{age}</td>
<td>{gender}</td>
<td>{hobby.join(',')}</td>
<td>{position.x+' '+position.y}</td>
</tr>
</tbody>
</table>
)
}
}
let person={
age: 100,
gender:'male',
hobby: ['basketball','football'],
position: {x: 10,y: 10},
}
ReactDOM.render(<Person {...person}/>, document.getElementById('root'));
import React from './react';
import ReactDOM from './react-dom';
//let element = <h1 className="title" style={{color:'red',fontSize:'24px'}}></h1>
//let element = React.createElement('h1',{className:'title',style:{color:'red',fontSize:'50px'}},'hello');
//console.log(JSON.stringify(element));
//function Welcome(props){
// return React.createElement('h1',{className:'title'},props.title);
//}
class Welcome extends React.Component{
render(){
return React.createElement('h1',{className:'title'},this.props.title);
}
}
let element = React.createElement(Welcome,{title:'标题'});
ReactDOM.render(element, document.getElementById('root'));
import createElement from './element';
class Component{
static isReactComponent = true
constructor(props){
this.props = props;
}
}
export default {
createElement,Component
}
const ReactElement = function(type,props) {
const element = {
type: type,
props: props,
};
return element;
}
function createElement(type,config,children){
let propName;
const props = {};
for (propName in config) {
props[propName] = config[propName];
}
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
props.children = Array.prototype.slice.call(arguments,2);
}
return ReactElement(type,props);
}
export default createElement;
function render(element,container){
if(typeof element == 'string'){
return container.appendChild(document.createTextNode(element))
}
let type,props;
type = element.type;
props = element.props;
if(type.isReactComponent){//如果为true说明它是一个类组件
element = new type(props).render();
type = element.type;
props = element.props;
}else if(typeof type =='function'){
element = type(props);
type = element.type;
props = element.props;
}
let domElement = document.createElement(type);
for(let propName in props){
if(propName === 'children'){
let children = props[propName];
children = Array.isArray(children)?children:[children];
children.forEach(child=>render(child,domElement));
}else if(propName === 'className'){
domElement.className = props[propName];
}else if(propName === 'style'){
let styleObj = props[propName];
/**
for(let attr in styleObj){
domElement.style[attr] = styleObj[attr];
}
*/
let cssText = Object.keys(styleObj).map(attr=>{
return `${attr.replace(/([A-Z])/g,function(){ return"-"+arguments[1]})}:${styleObj[attr]}`;
}).join(';');
domElement.style.cssText = cssText;
}else{
domElement.setAttribute(propName,props[propName]);
}
}
container.appendChild(domElement);
}
export default {render};
setState
import React from 'react';
import ReactDOM from 'react-dom';
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
this.state
赋值的地方import React from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 0
};
}
componentDidMount() {
this.timerID = setInterval(
() => {
//this.setState({number:this.state.number+1});
this.state.number = this.state.number + 1;
},
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
render() {
return (
<div >
<p> {this.state.number} </p>
</div>
);
}
}
ReactDOM.render(<
Counter />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
number: 0
};
}
handleClick = ()=>{
//this.setState({number:this.state.number+1});
//console.log(this.state.number);
//this.setState({number:this.state.number+1});
this.setState((state)=>(
{number:state.number+1}
));
this.setState((state)=>(
{number:state.number+1}
));
}
render() {
return (
<div >
<p> {this.state.number} </p>
<button onClick={this.handleClick}>+</button>
</div>
);
}
}
ReactDOM.render(<
Counter />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
name:'zhufeng',
number: 0
};
}
handleClick = ()=>{
//this.setState({number:this.state.number+1});
//console.log(this.state.number);
//this.setState({number:this.state.number+1});
this.setState((state)=>(
{number:state.number+1}
));
this.setState((state)=>(
{number:state.number+1}
));
}
render() {
return (
<div >
<p>{this.state.name}: {this.state.number} </p>
<button onClick={this.handleClick}>+</button>
</div>
);
}
}
ReactDOM.render(<
Counter />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {
name:'zhufeng',
number: 0
};
}
handleClick = ()=>{
this.setState((state)=>(
{number:state.number+1}
));
}
render() {
return (
<div style={{border:'1px solid red'}}>
<p>{this.state.name}: {this.state.number} </p>
<button onClick={this.handleClick}>+</button>
<SubCounter number={this.state.number}/>
</div>
);
}
}
class SubCounter extends React.Component {
render(){
return <div style={{border:'1px solid blue'}}>子计数器:{this.props.number}</div>;
}
}
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
false
的方式阻止默认行为。你必须显式的使用preventDefault
import React from 'react';
import ReactDOM from 'react-dom';
class Link extends React.Component {
handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
render() {
return (
<a href="http://www.baidu.com" onClick={this.handleClick}>
Click me
</a>
);
}
}
ReactDOM.render(
<Link />,
document.getElementById('root')
);
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
handleClick1 = () => {
console.log('this is:', this);
}
render() {
//onClick={this.handleClick.bind(this)
return (
<button onClick={(event) => this.handleClick(event)}>
Click me
</button>
);
}
}
class LoggingButton extends React.Component {
handleClick1 = (id,event) => {
console.log('id:', id);
}
render() {
return (
<>
<button onClick={(event) => this.handleClick('1',event)}>
Click me
</button>
<button onClick={this.handleClick.bind(this,'1')}>
Click me
</button>
</>
);
}
}
value
class Sum extends React.Component {
handleAdd = (event) => {
let a = this.refs.a.value;
let b = this.refs.b.value;
this.refs.c.value = a+b;
}
render() {
return (
<>
<input ref="a" />+<input ref="b"/><button onClick={this.handleAdd}>=</button><input ref="c"/>
</>
);
}
}
class Sum extends React.Component {
handleAdd = (event) => {
let a = this.a.value;
let b = this.b.value;
this.result.value = a+b;
}
render() {
return (
<>
<input ref={ref=>this.a= ref} />+<input ref={ref=>this.b= ref} /><button onClick={this.handleAdd}>=</button><input ref={ref=>this.result= ref} />
</>
);
}
}
class Sum extends React.Component {
constructor(props){
super(props);
this.a = React.createRef();
this.b = React.createRef();
this.result = React.createRef();
}
handleAdd = () => {
let a = this.a.current.value;
let b = this.b.current.value;
this.result.current.value = a+b;
}
render() {
return (
<>
<input ref={this.a} />+<input ref={this.b} /><button onClick={this.handleAdd}>=</button><input ref={this.result} />
</>
);
}
}
class Form extends React.Component {
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus = () => {
this.input.current.getFocus();
}
render() {
return (
<>
<TextInput ref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
class TextInput extends React.Component{
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus =()=>{
this.input.current.focus();
}
render(){
return <input ref={this.input}/>
}
}
class Form extends React.Component {
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus = () => {
this.input.current.getFocus();
}
render() {
return (
<>
<TextInput ref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
//Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
function TextInput (){
return <input/>
}
使用forwardRef
class Form extends React.Component {
constructor(props){
super(props);
this.input = React.createRef();
}
getFocus = () => {
this.input.current.focus();
}
render() {
return (
<>
<TextInput ref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
const TextInput = React.forwardRef((props,ref)=>(
<input ref={ref}/>
));
实现
function createRef(){
return {
current:null
}
}
class Form extends React.Component {
constructor(props){
super(props);
this.input = createRef();
}
getFocus = () => {
this.input.current.focus();
}
render() {
return (
<>
<TextInput myref={this.input}/>
<button onClick={this.getFocus}>获得焦点</button>
</>
);
}
}
function forwardRef(funcComponent){
return function(props){
let ref = props.myref;
return funcComponent(props,ref);
}
}
const TextInput = forwardRef((props,ref)=>(
<input ref={ref}/>
));
import React, {
Component,
useState,
useImperativeHandle,
useCallback,
useMemo,
useRef,
useEffect,
forwardRef,
useLayoutEffect
} from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component{ // 他会比较两个状态相等就不会刷新视图 PureComponent是浅比较
static defaultProps = {
name:'珠峰培训'
};
constructor(props){
super();
this.state = {number:0}
console.log('1.constructor构造函数')
}
componentWillMount(){ // 取本地的数据 同步的方式:采用渲染之前获取数据,只渲染一次
console.log('2.组件将要加载 componentWillMount');
}
componentDidMount(){
console.log('4.组件挂载完成 componentDidMount');
}
handleClick=()=>{
this.setState({number:this.state.number+1});
};
// react可以shouldComponentUpdate方法中优化 PureComponent 可以帮我们做这件事
shouldComponentUpdate(nextProps,nextState){ // 代表的是下一次的属性 和 下一次的状态
console.log('5.组件是否更新 shouldComponentUpdate');
return nextState.number%2;
// return nextState.number!==this.state.number; //如果此函数种返回了false 就不会调用render方法了
} //不要随便用setState 可能会死循环
componentWillUpdate(){
console.log('6.组件将要更新 componentWillUpdate');
}
componentDidUpdate(){
console.log('7.组件完成更新 componentDidUpdate');
}
render(){
console.log('3.render');
return (
<div>
<p>{this.state.number}</p>
{this.state.number>3?null:<ChildCounter n={this.state.number}/>}
<button onClick={this.handleClick}>+</button>
</div>
)
}
}
class ChildCounter extends Component{
componentWillUnmount(){
console.log('组件将要卸载componentWillUnmount')
}
componentWillMount(){
console.log('child componentWillMount')
}
render(){
console.log('child-render')
return (<div>
{this.props.n}
</div>)
}
componentDidMount(){
console.log('child componentDidMount')
}
componentWillReceiveProps(newProps){ // 第一次不会执行,之后属性更新时才会执行
console.log('child componentWillReceiveProps')
}
shouldComponentUpdate(nextProps,nextState){
return nextProps.n%3==0; //子组件判断接收的属性 是否满足更新条件 为true则更新
}
}
ReactDOM.render(<Counter/>, document.getElementById('root'));
// defaultProps
// constructor
// componentWillMount
// render
// componentDidMount
// 状态更新会触发的
// shouldComponentUpdate nextProps,nextState=>boolean
// componentWillUpdate
// componentDidUpdate
// 属性更新
// componentWillReceiveProps newProps
// 卸载
// componentWillUnmount
import React from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component{
static defaultProps = {
name:'珠峰架构'
};
constructor(props){
super();
this.state = {number:0}
}
handleClick=()=>{
this.setState({number:this.state.number+1});
};
render(){
console.log('3.render');
return (
<div>
<p>{this.state.number}</p>
<ChildCounter number={this.state.number}/>
<button onClick={this.handleClick}>+</button>
</div>
)
}
}
class ChildCounter extends React.Component{
constructor(){
super();
this.state = {number:0};
}
static getDerivedStateFromProps(nextProps, prevState) {
const {number} = nextProps;
// 当传入的type发生变化的时候,更新state
if (number%2==0) {
return { number:number*2};
}else{
return { number:number*3};
}
// 否则,对于state不进行任何操作
return null;
}
render(){
console.log('child-render',this.state)
return (<div>
{this.state.number}
</div>)
}
}
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.state = {messages: []}
this.wrapper = React.createRef();
}
addMessage() {
this.setState(state => ({
messages: [`${state.messages.length}`, ...state.messages],
}))
}
componentDidMount() {
this.timeID = window.setInterval(() => {//设置定时器
this.addMessage();
}, 1000)
}
componentWillUnmount() {//清除定时器
window.clearInterval(this.timeID);
}
getSnapshotBeforeUpdate() {//很关键的,我们获取当前rootNode的scrollHeight,传到componentDidUpdate 的参数perScrollHeight
return this.wrapper.current.scrollHeight;
}
componentDidUpdate(perProps, perState, prevScrollHeight) {
const curScrollTop = this.wrapper.current.scrollTop;//当前向上卷去的高度
//当前向上卷去的高度加上增加的内容高度
this.wrapper.current.scrollTop = curScrollTop + (this.wrapper.current.scrollHeight - prevScrollHeight);
}
render() {
let style = {
height: '100px',
width: '200px',
border: '1px solid red',
overflow: 'auto'
}
return (
<div style={style} ref={this.wrapper} >
{this.state.messages.map((message, index) => (
<div key={index}>{message} </div>
))}
</div>
);
}
}
ReactDOM.render(
<ScrollingList />,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
import { declareTypeAlias } from '@babel/types';
class Todos extends React.Component {
constructor(props){
super(props);
this.state = {
text:'',
todos:[]
}
}
handleAdd = (event)=>{
event.preventDefault();
this.setState({
todos:[...this.state.todos,{id:Date.now(),text:this.state.text}],
text:''
});
}
handleDelete(id){
this.setState({
todos:this.state.todos.filter(todo=>todo.id != id)
});
}
handleChange = (event)=>{
this.setState({
text:event.target.value
});
}
render() {
let todos = this.state.todos.map(todo=><li key={todo.id}>{todo.text}<button onClick={()=>this.handleDelete(todo.id)}>X</button></li>);
return (
<>
{this.props.name&&<h1>{this.props.name}</h1>}
<form onSubmit={this.handleAdd}>
<input type="text" value={this.state.text} onChange={this.handleChange}/>
<input type="submit"/>
</form>
<ul>
{ todos}
</ul>
{this.state.todos.length>0?`你现在${this.state.todos.length}件待办事项`:`你现在没有待办事项`}
</>
);
}
}
ReactDOM.render(
<Todos name="待办事项"/>,
document.getElementById('root')
);
import React from 'react';
import ReactDOM from 'react-dom';
class Todos extends React.Component {
constructor(props){
super(props);
this.state = {
text:'',
todos:[]
}
}
handleAdd = (event)=>{
event.preventDefault();
this.setState({
todos:[...this.state.todos,{id:Date.now(),text:this.state.text}],
text:''
});
}
handleDelete = (id)=>{
this.setState({
todos:this.state.todos.filter(todo=>todo.id != id)
});
}
handleChange = (event)=>{
this.setState({
text:event.target.value
});
}
render() {
return (
<>
{this.props.name&&<h1>{this.props.name}</h1>}
<TodoHeader text={this.state.text} handleAdd={this.handleAdd} handleChange={this.handleChange}/>
<TodoItems todos={this.state.todos} handleDelete={this.handleDelete}/>
<TodoFooter todos={this.state.todos}/>
</>
);
}
}
class TodoHeader extends React.Component{
render(){
return (
<form onSubmit={this.props.handleAdd}>
<input type="text" value={this.props.text} onChange={this.props.handleChange}/>
<input type="submit"/>
</form>
)
}
}
class TodoItems extends React.Component{
render(){
let todos = this.props.todos.map(todo=><li key={todo.id}>{todo.text}<button onClick={()=>this.props.handleDelete(todo.id)}>X</button></li>);
return (
<ul>
{ todos}
</ul>
)
}
}
class TodoFooter extends React.Component{
render(){
return (
<>{this.props.todos.length>0?`你现在${this.props.todos.length}件待办事项`:`你现在没有待办事项`}</>
)
}
}
ReactDOM.render(
<Todos name="待办事项"/>,
document.getElementById('root')
);