react的知识点详讲解细,灵活使用react的语法和外加react面试题

react组件创建的几种方式

createClass
这是react在ES5时期使用的创建组建的方式
var React = require("react");var Greeting = React.createClass({    propTypes: {    name: React.PropTypes.string   },  getDefaultProps: function() {    return {      name: 'Mary' //默认属性值    };  },    getInitialState: function() {    return {count: this.props.initialCount}; //初始化state  },    handleClick: function() {    //用户点击事件的处理函数  },  render: function() {    return <h1>Hello, {this.props.name}</h1>;  }});module.exports = Greeting;
在createClass中,React对属性中的所有函数都进行了this绑定,也就是如上面的hanleClick其实相当于handleClick.bind(this)class component
随着ES6的到来,带来了类和继承语法级别的支持,所以在ES6中,React推荐使用class的方式创建组件
 import React from 'react';class  extends React.Component {  constructor(props) {    super(props);    this.state = {count: props.initialCount};    this.handleClick = this.handleClick.bind(this);  }    //static defaultProps = {  //  name: 'Mary'  //定义defaultprops的另一种方式  //}    //static propTypes = {    //name: React.PropTypes.string  //}    handleClick() {    //点击事件的处理函数  }    //handleClick = () => {  //}    render() {    return <h1>Hello, {this.props.name}</h1>;  }}Greeting.propTypes = {  name: React.PropTypes.string};Greeting.defaultProps = {  name: 'Mary'};export default Greating;
而在面向对象的语法中类的属性通常被称作静态(static)属性,这也是为什么props还可以像上面注释掉的方式来定义。
用这种方式创建组件时,React并没有对内部的函数,进行this绑定,所以如果你想让函数在回调中保持正确的this,就要手动对需要的函数进行this绑定,有两种方式:
构造函数中使用this.handleClick = this.handleClick.bind(this);
函数声明时采用箭头函数,如注释中的handleClick = () => { return}
functional component
上面我们提到的创建组件的方式,都是用来创建包含状态和用户交互的复杂组件,当组件本身只是用来展示,所有数据都是通过props传入的时候,我们便可以使用Stateless Functional Component来快速创建组件。例如下面代码所示:
12345678910111213141516 import React from 'react';const Button = ({  day,  increment}) => {  return (    <div>      <button onClick={increment}>Today is {day}</button>    </div>  )}Button.propTypes = {  day: PropTypes.string.isRequired,  increment: PropTypes.func.isRequired,}
这种组件,没有自身的状态,相同的props输入,必然会获得完全相同的组件展示。因为不需要关心组件的一些生命周期函数和渲染的钩子,所以不用继承自Component显得更简洁。
比较
class component与createClass本质上没什么区别,只是一个支持ES6,一个不支持
functional component与class component相比,主要区别在于function component是无状态的,也没有生命周期函数,但是带来了以下几个优势:
没有了this的困扰,在class component中事件回调经常需要通过bind或者箭头函数绑定this
强制视图、逻辑分离,耦合更低。functional component是无状态组件,适合用于表现类组件的创建。
可读性、可测试性都得到提高。因为functional component是纯函数,指定input即可确定output
潜在的性能提升。虽然目前functional component相比class component并没有性能提升,但是React官方计划在未来为functional component做优化,避免不必要的检查和内存分配,比如这篇文章指出,通过合理的优化,functional component可以实现45%的性能提升
很多时候我们创建了functional component,但是后来又需要为组件添加一些状态或者context或者需要调用生命周期函数,此时不必把functional component改写成class component,使用react hooks或者recompose即可。
这里更推荐使用官方的react hooks,它不仅为functional component带来了使用状态、context、生命周期函数的能力,使其可以完成class component的功能,还避免了“包装地狱”的引入
“包装地狱”是目前react中很常见的一个问题,在使用context或者HOC或者render props的时候因为引入了无用的标签,很容易就产生了很深的标签嵌套。
参考

类组件和函数组件

render(){
 	return(
{/* return是单一的根点   */}}
jsx是语法糖,让我们写react的可读性更高
jsx是变量,是对象,可以写表达式

react组件定义的方式
react中有多少种组件创建的方式
React.createElement()
class User extends React.Component{}
无状态组件function User(props){}
高阶组件 function Hoc(child){}
Hocks组件

父亲传过来的组件是不可以被修改的
class user extends React.Component{
    constructor(props)
    super(props)
    // props 是不可以被修改的
}
default default User



// 在一个组件中调用另外一个组件
import React from 'react'
import { Child } from '@/components'
class user extends React.Component{
    construtor(props){
        super(props)
        this.state={
            msg: 'hello world'
        }
    }
}
render(){
    return(
        <div>
            <Child aaa='111' ccc={this.state.msg}></Child>
        </div>
    )
}
    export default User


定义一个子组件
import React from 'react'
// 无状态组件
function Child(props){
    return (
        <div>
            <h1>user的子组件</h1>
            // 无状态组件没有this
            <span>{props.aaa}</span>
            <span>{props.msg }</span>
        <div>
    )
}
expor default Child 

 
使用箭头函数的方式定义
const Child = (props) => (
 不要return 
<div>
<h1>箭头函数的方式定义组件第一种写法 </h1>
</div>
)
第二种写法
const Child = (props) => {
    return (
        <div>
            <h1>箭头函数的方式定义组件第二种写法</h1>
        </div>    
    )   
}


函数组件要比类组件的效率高
函数组件不需要创建对象
类组件需要创建对象 render(){}
无状态组件
import React from 'react'
function Person(props){
    return (
        <ul>
             <li></li>
             <li></li> 
             <li></li>
        </ul>
    )
}
// 指定属性默认值
Person.defaultProps={
    sex:'男',
    age: 18
}
// 渲染组件标签
const p1={
    name:'Tom',
    age: 18,
    sex: '女'
    }
    // 指定属性值的类型和必要性
    Person.propTypes={
        name: PropTypes.string.isRequired,
        age: PropTypes.number
    }
ReactDom.render(<Person name={p1.name} age={p1.age} sex={p1.sex}/>,
docuement.getElementById('example'))
const p2={
    name:'JACK'
} 
                    age="20"字符串类型    age={20}数字类型
ReactDom.render(<Person name={p2.name} age={p1.age} sex={p1.sex}/>,
docuement.getElementById('example1'))
...的作用
1.是打包
function fn(...as)fn(1,2,3)
2.解包
const arr1=[1,2,3] const arr2=[6,...arr1,9]
ReactDom.render(<Person {...p1}/>,document.getElementById('expamle1'))



refs的使用

*`


import React,{Component} from 'react'
export default class Ref extends Component{
    consturct(){
        super(props)
        // 定义方法
        this.showInput =this.showInput.bind(this)
        this.handleBlur=this.handleBlur.bind(this)
    }
    showInput (){
        const input=this.refs.content
        alert(input.value)
        // 新版本的写法
    }
    handleBlur(event){
        alert(event.target,value)
    }
    render(){
        return(
            <div>
                <input type="text" ref="content"/>
                // 新版本地的写法
                <input type="text" ref={input =>this.inputw=input}/>
                <button onClick={this.showInput}>提示输入</button>
                <input type="text" placeholder="失去焦点提示内容"
                onBlur={this.handleBlur}
                />
            </div>
        )
    }
}


在父组中传递一个参数
class App extends React.Component{
    constructor(props){
        super(props)
        // 初始化状态
        this.state={
            todo:[
                {id: "1", name: "吃饭"},
                {id: "2", name: "睡觉"}
                {id: "3", name: "看书"}
            ]
        }
    }
    this.addTodo=this.addTodo.bind(this)
}
// 方法定义在父组件中,子组件调用它
 addTodo(todo){
        this.state.todos.unshift(todo) // 不能这种写
        const { todos } =this.state
        todos.unshift(todo)
        // 更新状态
        this.setState({todos})
    }
fn(){
    const { list }=this.state
    list.map((item)=>{
        <div key={itme.id}>
            <li>{item.value}</li>
        </div>
    }))
}
render(){
    const { todos } = this.state
    return (
        {this.fn()}
        <div>
            <h1>simple TODO List</h1>
            // 在父组件中传递一个方法,在子组件中去调用这个方法,并且定义类型
            <Add count={todos.length} addTodo2={this.addTodo}/>
            <List todos={this.state.todos}/>
        </div>
    )
}



 List组件
class List extends React.Component{
    render(){
        // const {todos}=this.props.todo
        return(
            <ul>
               {
                   // =>就是放回 return
                   this.props.todos.map((todo,index)=>
                   // <li key={index}>{todo.name}</li>
                     {
                         return  <li key={index}>{todo.name}</li>
                     }
                   )
               }
            </ul>
        )
    }
}
List.propTypes={
    todos:PropTypes.array.isRequired
}


(子组件) 在父组件定义函数,传给子组件,子组件去调用这个方法	
Add组件 子组件不能直接改变父组件的状态 
状态在哪个组件,更新状态的行为就应该定义在哪个组件
class Add extends React.Component{
    constructor(props){
        super(props)
        this.add=this.add.bind(this) // 自定义方法加要this
    }
    add(){
        // 1.读取输入的数据
        const todo=this.todoInput.value.trim()
        // 2.检查和法性
        if(!todo){
                return
        }
        // 3.添加
        this.props.addTodo(todo)
        // 4.清除输入
        this.todoInput.value=''
    }
    render(){
        return (
            <div>
                <input type="text" ref={input=>this.todoInput=input}>
                // 操作的状态是在props
                <button onClick={this.add}>add #{this.props.count}</button>
            </div>
        )
    }
}
Add.propTypes={
    count:    propTypes.number.isRequired;
    addTodo2: propTypes.func.isRequired;
}
class List extends React.Component{
    render(){
        
    }
}


react 的类型检测

import   React,{component}  from  'react'
import   PropTypes from 'prop-types'
class Child3 extends React.Component {
constructor(props){
     super(props)
}
render(){
<div>
 	<h3>子组件-3</h3>
</div>
}
}
// 检测子组件的数据类型是写在子组件中
Child3.proptypes={
 	aaa:PropTypes.string
        bbb:PropTypes.string.bool.isRequired
}
export default Child3

import React from 'react'
import { Child3 }  from '@/components'
export default class PropTypes extends React.Component{
    render(){
        return(
            <div>
            <Child3 aaa={1000}>
            </div>
        )
    }
    
}

react的props.child


import React from 'react'
// 调用组件要引用它
import TodoHeader from './TodoHeader'
import TodoInput  from './TodoInput '
export default class App extends React.Component{
    render(){
        return (
            <Fragment>
                // 调用组件要引用它               x="1" y="2"
                <TodoHeader desc="今日事,今日毕" x={1} y={2}>   
                // 可以通过props传递任何东西
                <i> 待办事项列表(相当  于vue中的slot)</i>
                </TodoHeader>
                <TodoInput btnText="ADD"/>
            </Fragment>
            // <> 这个是相当于<Fragment>,它里面可以放很多的组件就是可以写多个同级的div标签或组件
            // <TodoHeader/>
            // </>
        )
    }
}

// 函数组件,无状态组件
import React from 'react'
// 函数组件,无状态组件
export default function TodoHeader(){
    conosole.log(props)
    return (
        <>
        <h1>
            {props.children}
        </h1>
        <h2>
            {props.desc}
        </h2>
        <p>{props.x+props.y}</>
        </>
    )
} 

// 类组件
import React from 'react'
// 函数组件,无状态组件
export default  class TodoInput extends Compoent{
    conosole.log(props)
    render() {
        return (
                <div>
                    <input type="text"/><button>{this.props.btnText}</button>
                </div>
        )
    }
} 



npm i  --save prop-types

在传夫父
子组件向父组件传值
子组件:
handleVal函数处理用户输入的字符,再传给父组件的handelEmail函数
var Child = React.createClass({
    handleVal: function() {
        var val = this.refs.emailDom.value;
        val = val.replace(/[^0-9|a-z|\@|\.]/ig,"");
        this.props.handleEmail(val);
    },
    render: function(){
        return (
            <div>
                请输入邮箱:<input ref="emailDom" onChange={this.handleVal}/>
            </div>
        )
    }
});
父组件:
通过handleEmail接受到的参数,即子组件的值
var Parent = React.createClass({
    getInitialState: function(){
        return {
            email: ''
        }
    },
    handleEmail: function(val){
        this.setState({email: val});
    },
    render: function(){
        return (
            <div>
                <div>用户邮箱:{this.state.email}</div>
                <Child name="email" handleEmail={this.handleEmail.bind(this)}/>
            </div>
        )
    }
});
React.render(
  <Parent />,
  document.getElementById('test')
);





react的传值

react组件传值,大概有下面几种方法:
props
context
redux
react-router 路由切换时通过url传值(少量非机密数据,其实也是props传)。

一、父组件传给子组件
父组件通过props传递给子组件;
//父组件中
<Child data={[1,2,3]}/>
//子组件中
console.log(this.props.data);

二、子组件传给父组件
父组件通过props向子组件传入一个方法,子组件在通过调用该方法,将数据以参数的形式传给父组件,父组件可以在该方法中对传入的数据进行处理
//父组件
import Child from './Child.js'import  React { Component } from 'react'
export default class Parent extend Compenent{
  getData=(data)=>{
    console.log(data);
  }
  render(){
    return (
      <div>
        父组件
        <Child getData={this.getData}/>
      </div>
    )
  }
}

//子组件
export default class Child extend compenent{
  state={
    data:[1,2,3]
  }
  render(){
    const {data}=this.state;
    return (
      <div>
        子组件
        <button onClick={()=>{this.props.getData(data)}}><button>
      </div>
    )
  }
}

三,路由传值。
1.props.params(推荐)
//设置路由
 <Router history={hashHistory}>
    <Route path='/user/:name' component={UserPage}></Route>
 </Router>

import { Router,Route,Link,hashHistory} from 'react-router';
class App extends React.Component {
  render() {
    return (      
        <Link to="/user/sam">用户</Link>
        // 或者
        hashHistory.push("/user/sam");
    )
  }
}

当页面跳转到UserPage页面之后,取出传过来的值:
export default class UserPage extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return(<div>this.props.match.params.name</div>)
    }
}

上面的方法可以传递一个或多个值,但是每个值的类型都是字符串,没法传递一个对象,如果传递的话可以将json对象转换为字符串,然后传递过去,传递过去之后再将json字符串转换为对象将数据取出来
//定义路由
<Route path='/user/:data' component={UserPage}></Route>
//设置参数
var data = {id:3,name:sam,age:36};
data = JSON.stringify(data);
var path = `/user/${data}`;
//传值
<Link to={path}>用户</Link>
//或
hashHistory.push(path);
//获取参数
var data = JSON.parse(this.props.params.data);
var {id,name,age} = data;

2.query(不推荐:刷新页面参数丢失)
query方式使用很简单,类似于表单中的get方法,传递参数为明文
//定义路由
<Route path='/user' component={UserPage}></Route>
//设置参数
var data = {id:3,name:sam,age:36};
var path = {
  pathname:'/user',
  query:data,
}
//传值
<Link to={path}>用户</Link>
//或
hashHistory.push(path);
//获取参数
var data = this.props.location.query;
var {id,name,age} = data;

3.state(不推荐,刷新页面参数丢失)
state方式类似于post方式,使用方式和query类似
//设置路由
<Route path='/user' component={UserPage}></Route>
//设置参数
var data = {id:3,name:sam,age:36};
var path = {
  pathname:'/user',
  state:data,
}
//传值
<Link to={path}>用户</Link>
//或
hashHistory.push(path);
//获取参数
var data = this.props.location.state;
var {id,name,age} = data;

特别提示:
1,获取参数时要用this.props.match.params.name
2,如果在子组件里打印要记得传this.props,如下:
class Todolist extends Component {
    render() {
       return (
           <DocumentTitle title="todolist">
           <div id="home-container">   
           <section>
              <TodolistList {...this.props}/> //不传的话this.props为空对象
           </section>                   
           </div>
           </DocumentTitle>
       );
    }
 }
export default Todolist;

四,非父子组件且嵌套关系复杂的组件之间数据的传递。
通过redux来传值的实现
1,我们先写一个createAction的函数
export function setAnalysisParams(params) {
  return {
    type: SET_ANALYSIS_PARAMS,
    result: params
  }
}

2,在reducer里面:
export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case SET_ANALYSIS_PARAMS:
      return {
        ...state,
        params: action.result
      };
    default:
      return state;
  }

当action触发reducer时,会把action的result传给reducer的params。写好这里,我们就可以在组件中传给adction params了。
@connect(
  () => ({
  }),
  {
    setAnalysisParams
  })

先把actionCreator拿出来。
在组件的某个需要的地方,可以直接向它传我们要放进redux里的数据:
this.props.setAnalysisParams({
        someModels
      });

这时,我们就可以在另外一个组件中取到刚刚放进去的数据。
另外一个组件:
@connect(
  state => ({
    example: state.clinic.params
  }),
  {}
)

把redux中的params数据映射到example上。
下面,就可以用了:
 const {someNames, ...} = this.props.example; //取出数据名

token是 123456LshLsh!

组件通信

父子通信
import React from 'react'
export default class Father extends React.Component{
    constructor(props){
        super(props)
        this.state={
            message:'hello'
        }
    },
    componentDidMount(){
        setTimeout(()=>{
        this.setState({
            message:'world'
         })
        },2000)
    }
    render(){
        // 调用子组件
        return <Child message={this.state.message}></Child>
    }
}

 子组件
class Child extends Component{
  render(){
        return <div>{this.props.message}</div>
  }
}

子父通信
子组件向父组件通信,也需要父组件向子组件传递props,只
是作用域为父组件自身的函数,子组件调用该函数,
将子组件想要的传递的信息,作为参数,传递到父组件的作用域中
class Parent extends Component{
this.state = {
message: 'hello'
};
transferMsg(msg){
this.setState({
message
});
}
render(){
return  <div>
            <p>child msg: {this.state.message}</p>
           <Child transferMsg = {msg => this.transferMsg(msg)} />
</div>
}
}

class Child extends Component{
componentDidMount(){
setTimeOut( () => {
this.props.transferMsg('world')
},2000)
}
render(){
return <div>child</div>
}
}

受控组件和非受控组件


class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}


withRouter



高阶组件中的withRouter, 作用是将一个组件包裹进Route里面, 然后react-router的三个对象history, location, match就会被放进这个组件的props属性中.

git clone ssh的地址
npm i 下载node_modeul
npm  set registry  镜像地址

那个git checkout
之后
git pull 拉取最新的分支

import React,{ Component } from "react"
// 定义类组件
class LoginFrom extends Component{

} 
export default LoginFrom 


Es6的 import as obj from ‘’

index.js
export  function fn1(data){
    console.log(1)
}
export function fn1(data){
    console.log(2)
}


import  * as from  './index.js'
Fn.fn1() // 1
Fn.fn2() // 2


重命名exportimport,如果导入的多个文件中,变量名字相同,即会产生命名冲突的问题,
为了解决该问题,ES6为提供了重命名的方法,当你在导入名称时可以这样做。


/*************test1.js*****************/
export let myName = "我来自test1.js";
/*************test2.js*****************/
export let myName = "我来自test2.js";

/*************index.js****************/
import {myName as name1} from "./test1.js";
import {myName as name2} from "./test2.js";
console.log(name1); //我来自test1.js
console.log(name2); //我来自test2.js


第二种写方法
action-Type文件是定义变量防止重名
export  const ChAN="EUEOWWE"
export  const Hew="WEIIE"


定义action的文件
import * UI from "./action-type"
export const changRootFont = (value)=>{
    return {
        // es6的暴露
        type: UI.ChAN,
        value
    }
}
export const changFace = (faceIndex)=>{
    return {
        type: UI.Hew,
        faceIndex
    }
}


React.Fragment

React.Fragment
官方文档:
React 中一个常见模式是为一个组件返回多个元素。Fragments 可以让你聚合一个子元素列表,并且不在DOM中增加额外节点。
Fragments 看起来像空的 JSX 标签:

render() {
  return (
    <>
      <ChildA />
      <ChildB />
      <ChildC />
    </>
  );
}

一个常见模式是为一个组件返回一个子元素列表。以这个示例的 React 片段为例:
class Table extends React.Component {
  render() {
    return (
      <table>
        <tr>
          <Columns />
        </tr>
      </table>
    );
  }
}




class Columns extends React.Component {
  render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    );
  }
}



你可以像使用其它元素那样使用 <></>。
另一种使用片段的方式是使用 React.Fragment 组件,React.Fragment 组件可以在 React 对象上使用。 这可能是必要的,如果你的工具还不支持 JSX 片段。 注意在 React 中, <></><React.Fragment/> 的语法糖。
class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}

带 key 的 Fragments
<></> 语法不能接受键值或属性。
如果你需要一个带 key 的片段,你可以直接使用 <React.Fragment /> 。
一个使用场景是映射一个集合为一个片段数组 — 例如:创建一个描述列表:
function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // 没有`key`,将会触发一个key警告
        <React.Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </React.Fragment>
      ))}
    </dl>
  );
}


key 是唯一可以传递给 Fragment 的属性。在将来,我们可能增加额外的属性支持,比如事件处理。


条件渲染

通过请求回来的数据进行渲染
判断它的长度是否大于0
constructor(props){
super(props){
title:'代办事项列表',
desc:'今日事,今日毕',
todos:[{
id:1,
title:'吃饭',
isCompleted:ture
},{
       id:2,
title:'睡觉',
isCompleted:false
}]
}
}
render(){
return (
<Fragment>
// 判读有没有渲染完成,完成在显示出来
{this.state.todos[0].isCompleted?'完成':'未完成'}{this.state.todos[0].isCompleted&&'完成'}
</Fragment>
)
}

利用{...state}展开预算符,来获取
把需要的值在组件中传过去
export default TodoList extends Todolist 
render(){
  <ul>
      {
          this.props.todos.map(todo={
              return(
                  // 传替数据
                  <TodoItem
                  key={todo.id}
                  // 通过展开运算符来传值
                  {...todo}
                  >
          )
       })
      }
  </ul>  
}


 // 在例外一个组件进行接收
render(){
    return(
        <Fragment>
            <TodoHeader
            desc={this.state.desc}
            >
            </TodoHeader>
            <TodoInput>
            // 接收数据
            <TodoList todos={this.state.todos}/>
        </Fragment>
    )
}



//问题:如何将一个数据的数组转换为一个标签数组?
const names=['jq','zp','an','react','vue']
// 创建虚拟dom
<div id='example1'></div>
const ul=<ul>
{
names.map((name,index)=><li key={index}>{name}</li>)
}
</ul>//2. 渲染dom
React.render(ul,documentById('example1'))

函数组件的写法
<div id='example1'></div>
<div id='example2'></div>
<script>
// 1,定义组件
/*方式1:工厂函数组件(简单组件)*/
function MyComponent(){
    return <h2>工厂函数组件(简单组件)</h2>
}
/*方式2: ES6类组件(复杂组件)*/
class MyComponent2 extends React.Component{
    console.log(this)// this为组件的实列对象   
        render(){
        return <h2>ES6类组件(复杂组件)</h2>
    }
}
// 2.渲染组件标签
ReactDom.render(<MyComponent/>,documentById('example1'))
ReactDom.render(<MyComponent/>,documentById('example2'))
</script>


 读取某个状态值
this.state.状态名
更新状态-->组件界面更新
this.setState({
stateProp1:value1,
stateProp2:value2
})

constructor(){
super(props) 
// 初始化状态
this.state={
isLikeMe:false
}
// 将新增方法中的this强制绑定为组件对象
this.handleClick = this.handleClick .bind(this)
}

handleClick(){
// 得到状态并且取反
const isLikeMe=!this.state.isLike
//更新状态
this.setState({isLikeMe})
}





react的文件介绍

使用脚手架的步骤
cnpm install create-react-app -g

create-react-app 项目名

npm start

npm run eject 把脚手架原本隐藏封装的脚本,还原回来
注意:在执行eject时,会报错。
解决:先创建本地git仓库,并把代码进行本地提交。

cd react-antd-cms (cd 项目名)
git init
git add .
git commit -m ‘first commit’
npm run eject
执行npm run eject会在package.json,生成配置一些环境
? Are you sure you want to eject? This action is permanent. y 就会生成有一堆东西
为什么使用npm run eject
其中:
1.node_modules是各个插件存放位置
2.public用于放置静态资源,里面的资源不会参与构建
3.src是源码文件,一般做开发就在这个文件夹,会参与打包构建

重点来了:
在package.json中:
只有三个依赖,分别是react,react-dom,react-scripts,依赖为什么这么少,
是因为像webpack,babel等等都是被creat react app封装到了react-scripts这个项目当中,
包括基本启动命令 都是通过调用react-scripts这个依赖下面的命令进行启动的,
creat react app搭建出来的项目默认支持这4种命令,start以开发模式启动项目,
build将整个项目进行构建,test进行测试,eject,会将原本creat react app对webpack,
babel等相关配置的封装弹射出来
,如果我们要将creat react app配置文件进行修改,现有目录下是没有地方修改的,
此时,我们就可以通过eject命令将原本被封装到脚手架当中的命令弹射出来,然后就可以在项目的目录下看到很多配置文件

1.在scripts中start的文件,来修改端口号
找到
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
改为3000
2.vue识别@
react不识别 alias可以@
别是路径的问题
找到resolve.alias
在webpack.config.js
loaders把浏览器不认识的文件打包成浏览器识别的文件
sass 继承 混入 混合 解决csss的作用域

resolve配置alias
‘@’:path.resolve(__dirname,’…/src’)

file-loader是文件的loader
overlay:false
proxy:proxy
改了配置文件,要重启项目
favicon.icon 的生成
3.favicon 制作
找免费的网站
下载是32*32
4.sass的安装
react的文档都是分开的
flux的facebook的
sass只能cnpm安装
cnpm i node-sass -S 是运行环境安装在是-S 工具是-D
mainifest.json文件要
src中的index.js中的,相当于main.js,如果把它改成了main.js
在webpack文件也要改入口文件
引入react-dom要引react

5.代理
安装axios
cnpm install axios -D
在src中新建utils(app).js
在有状态组件一定要render
和无状态组件一定要render,
在componentDidMount中,调生命周期

在create-react-app.dev/docs/proxying-api-requests-in-development

5.1安装
5、本地环境怎么配置代码

安装 cnpm install http-proxy-middleware -D
cnpm install http-proxy-middleware --save
在src新建setupProxy.js文件 (新建代理文件 src/setupProxy.js)
看文档 setupProxy
const { createProxyMiddleware } = require(‘http-proxy-middleware’);
module.exports = function(app) {
app.use(
‘/api’,
createProxyMiddleware({
target: ‘http://xxx.com’,// 目标服务器
changeOrigin: true,
})
);
};

重启服务器
在package.json中,
1 开启
2 关闭
0
“eslintConfig”: {
“extends”: “react-app”
“rules”:{
“eqeqeq”: false
}
},

找eslint的文档

amiate文档变了

6.cnpm i react-router-dom -D 使用路由,必须先安装

新建views 组件名大写

无状态组件,可以服用的子组件

render是返回jsx的对象
home有10个组件,都有样式
放在一个文件中style.scss

安装异步加载组件
text一般是4个字
安装这个可以动态加载组件
react-loadable
loadable-components
安装 npm i @loadable-component 路由的赖加载
在需要的文件去引入
import loadable from ‘@loadable-component’
react 使用@loadable/component 实现路由动态懒加载

在app.js引入路由
import { HashRouter } from ‘react-dom’

在app.js引入抛出的路由
布局栅格系统
Layout

Link
现在,我们应用需要在各个页面间切换,如果使用锚点元素实现,在每次点击时,页面被重新加载,React Router提供了组件用来避免这种状况发生。当 你点击时,url会更新,组件会被重新渲染,但是页面不会重新加载
点击Link后,路由系统发生了什么?

Link 组件最终会渲染为 HTML 标签 ,它的 to、query、hash 属性会被组合在一起并渲染为 href 属性。虽然 Link 被渲染为超链接,但在内部实现上使用脚本拦截了浏览器的默认行为,然后调用了history.pushState 方法(注意,文中出现的 history 指的是通过 history 包里面的 create*History 方法创建的对象,window.history 则指定浏览器原生的 history 对象,由于有些 API 相同,不要弄混)。history 包中底层的 pushState 方法支持传入两个参数 state 和 path,在函数体内有将这两个参数传输到 createLocation 方法中,返回 location 的结构如下:
location = {
pathname, // 当前路径,即 Link 中的 to 属性
search, // search
hash, // hash
state, // state 对象
action, // location 类型,在点击 Link 时为 PUSH,浏览器前进后退时为 POP,调用 replaceState 方法时为 REPLACE
key, // 用于操作 sessionStorage 存取 state 对象
};

系统会将上述 location 对象作为参数传入到 TransitionTo 方法中,然后调用 window.location.hash 或者window.history.pushState() 修改了应用的 URL,这取决于你创建 history 对象的方式。同时会触发history.listen 中注册的事件监听器。
NavLink
是的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有

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

·····

无状态的组件(函数组件)和受控组件和非受控组件

函数组件没有this的指向
import React from 'react' 

函数式组件本身没有自己的内部状态 state,数据依赖于 props 的传入,所以它又称无状态组件。

函数组件没有状态
1.函数式组件不会被实例化,整体渲染性能得到提升
2.没有state ,数据依赖props的传入(无状态组件)
3.函数式组件无访问生命周期的方法

什么时候使用函数式组件
函数式组件相比类组件,拥有更好的性能和更简单的职责,十分适合分割原本庞大的组件,未来 React 也会对函数式组件进行一系列的优化

函数组件是有状态的组件
类组件是状态的组件

受控组件和非受控组件的区别
受控组件(没有状态,通过props获取外部的数据)
非受控组件(有状态)











react是单向数据流,怎么实现数据的双向绑定



import React from "react"
import ReactDOM from "react-dom"
 
export default class DataBind extends Comonent{
    constructor(){
        super()
        this.state = {
            value: "Name"
        }
    }
    handleChange(e){
        this.setState({
            value : e.target.value
        })
    }
    
    render(){
        return(
        <div style={{color:'black'}}>
		 <input value={this.state.value} onChange={this.handleChange.bind(this)}></input>
		 <p>{this.state.value}</p>
		</div>
        )
    }
    



react的面题

Keys 是React在操作列表中元素被修改,添加,或者删除的辅助标识.
在开发过程中,我们需要保证某个元素的key 在其同级元素中具有唯一性,在ReactDiff算法中React会借助元素的Key值来判断该元素是新创建的还是被移动而来的元素,React会保存这个辅助状态,从而减少不必要的元素渲染.此外,React还需要借助Key值来判断元素与本地状态的关联干洗,因此我们在开发中不可忽视Key值的使用.
什么是可以选择传递给setState的第二个参数,它的目的是什么?
一个回调函数,当setState结束并重新呈现该组件时将被调用。
传入 setState 函数的第二个参数的作用是什么?
该函数会在setState函数调用完成并且组件开始重渲染的时候被调用,我们可以用该函数来监听渲染是否完成:
this.setState(
  { username: 'tylermcginnis33' },
  () => console.log('setState has finished and the component has re-rendered.')
)


现在使用的react16.0的版本
react是什么?
react使用于构建用户界面的js的框架,因此react只负责解决view层的渲染
Immutable优点:
减少内存的使用
并发安全
降低项目的复杂度
便于比较复杂数据,定制shouldComponentUpdate方便
时间旅行功能
函数式编程
Immutable缺点:
学习成本
库的大小(建议使用seamless-immutable)
对现有项目入侵严重
容易与原生的对象进行混淆
react优化性能?
1.shouldComponentUpdate
2.使用react-loadable代码分割,按需加载
3.使用React.Fragment或者使用一个空标签,避免添加
额外的dom

1.减少diff算法触发次数
3:Key
  对于数组形式的数据,遍历时React会要求你为每一个数据值添加Key,而Key必须时独一无二的,在选取Key值时尽量不要用索引号,因为如果当数据的添加方式不是顺序添加,而是以其他方式(逆序,随机等),会导致每一次添加数据,每一个数据值的索引号都不一样,这就导致了Key的变化,而当Key变化时,React就会认为这与之前的数据值不相同,会多次执行渲染,会造成大量的性能浪费。所以只在万不得已时,才将数据的Key设为索引号。
3.setState

片段(碎片)

要在render(),同时返回多个元素,可以使用碎片
可以使用<React.Fragment></React.Fragment> 

import React from 'react'
function Qfmodel(props){
    return(
        <div><h3>model</h3></div>
    )
}
function Qfmodel2(props){
    return(
        <div><h3>model2</h3></div>
    )
}
// export default class Fragment extends React.Component{
//     // render(
//     //    <div></div> 没有return
//     // )
//     // <MyDialog></MyDialog>
//     // <MyDialog></MyDialog> 两个组件,不能同时并列返回,返回多个元素,要用react内置的多个元素
//     render(){
//         return(
//             // React.Fragment,可以抛出多个元素,可以返回多个元素,片段
//             <React.Fragment>
//               {/* <MyDialog></MyDialog> */}
//               <Qfmodel></Qfmodel>
//               <Qfmodel2></Qfmodel2>
//             </React.Fragment>
//         )
//     }
// }
// 片段的第二种写法
export default class Fragment extends React.Component{
    // render(
    //    <div></div> 没有return
    // )
    // <MyDialog></MyDialog>
    // <MyDialog></MyDialog> 两个组件,不能同时并列返回,返回多个元素,要用react内置的多个元素
    render(){
        return(
            // React.Fragment,可以抛出多个元素,可以返回多个元素,片段
            <>
              {/* <MyDialog></MyDialog> */}
              <Qfmodel></Qfmodel>
              <Qfmodel2></Qfmodel2>
            </>
        )
    }
}
// 在同一的出口,把它抛出去

react状态管理

状态工具
mobx  --写法非常灵活,非常适合小写类项目
mobx-react 是把mobx和react连接起来的工具
cnpm i mobx-react   -S
在app.js引入
import Provider from  'mobx-react  '
<Provider>
</Provider>


babel把新的语法转换为浏览器可以识别的语法

在react 
在工作中脚手架的环境中使用mobx,也需要安装2个插件
mobx用安装插件
cnpm i @babel/plugin-proposal-class-properties -D
在babelrc.json
cnpm i babel-eslint -D
插入一段代码
后重启项目

多翻文档
方法复用,可以使用同一个方法,传参数,来控制

redux
mobx是actions是相当于mutations

axios的请求原理,封装的过程

纯函数,固定的输入,得到唯一的输出
安装mobx
cnpm i  mobx  -S
export default class todolist(){
    
}


新建一个store 
在里面新建modules
在store中新建index.js

mutations官方建议唯一改变state的属性
mobx 需要用上下文

不在componentDidMount,会调用调两次
脚手架,也需要这样配置
mobx小公司用     redux大公司用
antd按需加载   
在app.js引入样式
react没有全局和局部组件之分
cnpm i antd -S  代码要用  
引入样式文件
~这个不需要
import 'antd/dist/antd.css'  js的引入方式
import '~antd/dist/antd.css' css的引入方式
在需要的文件中引入需要的组件
antd Design是谷歌公司
antd Design Mobile
表单是最复杂组件之一

react的生命周期

 初始化是会执行以下4钩子函数   
constructor
componentWillMount 被费用
render
componentDidMount
页面初始化执行下面的4个钩子函数

Mounting(挂载阶段)  初始化的时候,会执行挂载阶段的钩子函数
constructor()
static getDerivedStateFromProps() 这个生命周期,必须要有返回值  少用
这个生命周期是当父组件传props,或者state发生变化的时候会执行
static getDerivedStateFromProps() {  // 不常用
    return null
}

render()  state变化render变化
componentDidMount() 相当于vue的mounted  这个生命周期很重要,表示dom,就准备绪,
动态数据渲染完成  开启长连接,开定时器,调接口
componentWillMount() 相当于vue的Beforemount 
componentWillMount现在使用的少,使用了会报错



更新阶段 要改变state
更新执行的是以下4个钩子函数
shouldComponentUpdate   
render
getSnapshotBeforeUpdate
componentDidUpdate


shouldComponentUpdate(){}  性能优化  少用
 // 修改Component报错  shouldComponentUpdate dom的diff运算的开关 当前的页面组件要更新?
    // dom的diff运算,虚拟dom的对比,旧的虚拟dom和新的虚拟dom的对比,找到差异,找到之后更新页面
    shouldComponentUpdate(){  // 更新
        return true           // return false报错
  }
  // 要使用下面的钩子函数,必须要把开关打开 shouldComponentUpdate中返回的是return true 
    // 下面的钩子函数要和 componentDidUpdate一起使用
    getSnapshotBeforeUpdate(){  少用
        console.log('------- getSnapshotBeforeUpdate')
        return null
    }
    componentDidUpdate(){ // 相当于Updated
        console.log('------- componentDidUpdate')
    }

卸载阶段
销毁阶段就一个钩子函数
 // 卸载阶段 关闭长连接  关闭定时器 
    componentWillUnmount(){
        console.log('-------componentWillUnmount')
    }

4 4 1 
react的路由有三个包
react-router
react-router-dom
react-router-native

在npm中查,react-router-dom
在npm中 点React Training
soucer
进入之后,到最下找到react-router 网站是https://reactrouter.com/web/guides/quick-start

函数组件路由失效,所以用hooks 16.8支持hooks
路由都是组件

路由的安装
cnpm i  react-router-dom -S   包含所有的路由

1.在app.js中引入
import { HashRouter } from  'react-router-dom'import { HashRouter as xxx改名字 } from  'react-router-dom'
xxx表示改名字

 HashRouter 是组件  
HashRouter 和 BrowserRouter 的区别
BrowserRouter 相当于vue中的   history模式
 HashRouter和BrowserRouter区别是
 HashRouter带有#号,页面部署不会出现404
 BrowserRouter是没有#号,页面部署会出现404

react没有router的配置,自己手动配置

2.import {
   HashRouter
   BrowserRouter
   NavLink 
   Route,
   Switch,
   Redirect  // 重定向
}

LInk   和 NavLink的	区别
LInk   手动写高亮样式     相当于a标签
NavLink有高亮的样式      相当于a标签
activeClassName


根据url,匹配相应的组件,一一对应,多少个链接,多少个视图,所有的视图,
都要通过Router来渲染
<NavLink to='/home'>首页</NavLink>
<NavLink to='/hoc'>首页</NavLink>
//<Route path='/home' Component={大写的组件名}></Route>
<Route path='/home' Component={Home}></Route>
<Route path='/home' Component={hoc}></Route>
react没有react-view


1.在views中,把路由抛出去 2.在app.js,import Routes from '  '
export default[
    {
        id:1,
        path:'/jsx',
        compontent:JSx,
        text:'jsx的学习'
     },
      {
        id:2,
        path:'/event',
        compontent:Event,
        text:'事件绑定'
     },
]

上下文

上下文
弄一个上下文把,状态管理套起来
react,可以有多个上下文
    <HashRouter>
    // HashRouter是下面的上下文
        <fragement></fragement>
    </HashRouter>


// vue中集成路由路由
new Vue({
router:router,
store:store
})

为了让上下文起作用
react可以有多个上下文,按需加载
在mian.js先挂载后引入

## 组合

```javascript
组合是代码的复用,组件的嵌套
react的组件的复用是用组合,而不是继承
无状态组件,没有state,没有render,返回的是jsx,性能好 ,要用组件,可以使用类组件

 这是组合,不是插槽,在vue中 自定义组件中插入内容,可以使用插槽 
第一种写法
写好组件
// 通过props,来接受传过来的组件或jsx语法
// 使用无状态组件,可以提高浏览器的性能
import React from 'react'
import './style.scss'
export default function Model(props){
    return(
        <div className="model">
            <div>标题</div>
            // 通过props,封装好的组件当成变量传过
            { props.children }
        <div>
            <button>取消</button>
            <button>确定</button>
        </div>
        </div>
    )
}
// 在统一出口,进行抛出


  进行复用
import React, { Component } from 'react'
/* export default class Combian extends Component这种写是错误的
   应该还是下面的这种引入
   export default class Combian extends Component

*/
import { Model }  from '@/components'
// 无状态组件
function Delepane(props){
    return(
        <div>
            <h1>你要删除当前的文件?</h1>
        </div>
    )
}
function Delshure(props){
    return(
        <div>
            <h1>你确定要删除?</h1>
        </div>
    )
}
export default class Combian extends React.Component{
  render(){
      return(
          <div>
              <h1>学习组合</h1>
                {/* 调用组件 */}
              <Model>
                 // 传组件或jsx语法,都是当成变量传过去
                 <Delepane></Delepane>
                 <Delshure></Delshure>
              </Model>

              <Model>
                {/* 调用组件 */}
                 <Delshure></Delshure>
              </Model>
          </div> 
      )
  }
}

或第二种进行复用
export default class Combian extends React.Component{
  render(){
      return(
          <div>
              <h1>学习组合</h1>
              调用
              <Model>
                  {/* 这是组合,不是插槽,在vue中自定义组件中插入内容,可以使用插槽 */}
                  <h3>你确定要删除?</h3>
              </Model>

              <Model>
                  {/* 这是组合,不是插槽,在vue中自定义组件中插入内容,可以使用插槽 */}
                  <h3>你确定要删除?</h3>
              </Model>
          </div>
      )
  }
}


combian文件,在这里调用组件
import React, { Component } from 'react'
/* export default class Combian extends Component这种写是错误的
   应该还是下面的这种引入
   export default class Combian extends Component

*/
import { Model, Model2 }  from '@/components'
// 无状态组件
function Delepane(props){
    return(
        <div>
            <h1>你要删除当前的文件?</h1>
        </div>
    )
}
function Delshure(props){
    return(
        <div>
            <h1>你确定要删除?</h1> 
        </div>
    )
}
function ModelTitle1(props){
    return (
        <div>
            温馨提示
        </div>
    )
}
function ModelTitle2(props){
    return (
        <div>
            警告
        </div>
    )
}
function ModelContent(props){
    return (
        <div>
             快毕业了
        </div>
    )
}
function ModelButton(props){
    return (
        <div>
            <button>我知道了,我会好好复习一下的了</button>
        </div>
    )
}
export default class Combian extends React.Component{
  render(){
      return(
          <div>
              <h1>学习组合</h1>
                {/* 调用组件 */}
              <Model>
                 <Delepane></Delepane>
                 <Delshure></Delshure>
              </Model>

              <Model>
                {/* 调用组件 */}
                 <Delshure></Delshure>
              </Model>
              <hr/>
              {/* ModelTitle1,不是变量,是组件,注意它的写法 */}
              // title={<ModelTitle1></ModelTitle1>} 这里传的是组件,不是变量
              <Model2 
              title={<ModelTitle1></ModelTitle1>}
            //   content={<ModelContent/>}
              button={<ModelButton/>}
            >
                <div><h1>快要毕业了</h1></div>
                <input defaultValue="请填写好"/>
              </Model2>
          </div>
      )
  }
}

当一个组件需要其他组件组合的时候,组合作做不同需求是时,可以使用组合

DelModel 是继承Model
class DelModel extends Model{}
DelModel 是继承DeleteImages  DelModel是DeleteImages的子类
class DeleteImages extends DelModel {}

react的面试题
组件的复用是用组合
 

react的语法

工程项目
安装react
安装react脚手架
npm install -g create-react-app 
create-react-app 文件夹名  
   cd 文件夹:
               npm init   (然后一路回车)初始化 package.json,它是 NodeJS 约定的用来存放项目的信息和配置等信息的文件。
                npm install --save react react-dom  ( 在该目录下导入react和react-dom)
                npm install --save  react-router-dom   (react路由,以后会用到)
 打开 npm  start 成功√

1.新的技术
安装react
import 同时
export出去
图片可以

import 

export{
home,
home1
}

generaor 的语法糖是async await
react是facebook发明的
jsx变量,对象 ,可嵌套的,可以是表达式(得到的是值) 单括号 {this.init()}表达式
this的指向是指,当前组件的实例
jsx不是强制的,但是jsx让代码更具可读性
jsx使用的是单大括号
render是生命周期的钩子函数
render(){return (
<div>
<h1>ttytyyt</h1>
</div>
)}

在views是home index.js    user  index.js组件
vue的组件定义
react有多少种常见组件的方法
1.ES5组件 React.createElement()
2.类组件 class User extends React.Component{} 面向对象的组件
    es6创建的组件
    class User extends React.Component{
        
    }

3.无状态(函数) function User(props){}
 没有state和this  父自定义属性,子组件用props来接收
4.高阶组件 function Hoc(child){}
5.hocks组件


react是表达式
props不能修改,只能读

在components ,中定义一个出口,定义一个child组件,有一个index.js

state状态,可以放请求的数据,显示隐藏
响应是单向的
state中的数据,是单向的
在react中定义的事件
在react中,事件名大写
onClick  onInput 事件名字的方式
onKeydown
实例方法可以通过this
this访问的是实列属性
类方法是静态方法
<button onClick={this.click.bind(this)}></button>
在构造函数里面,this.click1=this.click.bind(this)
 
箭头函数this的指向是,方法是指向当前的实例


用arg接收,自定义参数在第一,事件对象在最后
在state中定义事件
jsx注释
{/*注释*/}
react 正向,方向不可以
setstate的操作是异步的
可以用时间,类似setTimeout()

//改变state,是异步操作,可以用回调函数
状态变化视图变化,反过来不可以
this.setState({
 msg:'',
aaa:'1'
},function(){
console.log('msg数据更新')
})

// 当state发生变化时,视图自动发生变化(反过来,不可以)

e.target.value








npm install babel-loader -D
npm install @babel/preset-react -D

js基础数据类型:number string null undefined string boolean,存放在栈内存
js引用数据类型:Object (Array,Date,RegExp,Function),存放在堆内存

如何判断array对象
可以使用Array.isArray()或者Object.prototype.toString.call()判断


{}可以写表达式  {this.state.bol?<h1>g1</h1>:<h2>rwerw</h2>}
单条件为三目 &&
this.state.msg &&组件 
标签
if  elseif 做条件渲染
在同级组件
根元素加className 
.User{
  .box{
  color:red
}
}
在组件内部用一个样式文件
react的写法灵活
style是对象 style={对象}
style={{color:'red'}}

改变state的语法用this.setState
switch匹配成功,后面不执行,性能高
if 一行一行的指向
v-if的显示隐藏用switch
var ele=null 减少return 
无状态组件,  无状态state  速度快
类组件 有在状态state

jsx对象
{}大括号写语句
方法和render同级

写了方法,return出去

深浅复制
render只执行一次
render先执行,后执行后面的

map可以做列表循环
数据处理用函数的形式
封装方法,大量数据的时候
key加在div的外面

table在render中

理解深浅拷贝以及深浅拷贝的方法
vue缓存路由.懒加载,图片懒加载,日期库
Vue keep-alive本地路由缓存和图片懒加载

key的 作用
表单在vue或react是单闭合标签
在index.js 移入 抛出
在main引入,调用
方法是在render中,同等的
change是失焦的时候触发
oninput是输入触发

表单
setState是改变state
defaulevalue  不是绝对的受控表单,没有声明式的影响
value
表单是变的是value

defaulevalue和value的区别

非受控表单 与state无关
不受响应式的控制
ref就是获取dom 
ref="address"
this.refs.address

ref不建议使用非受控表单
ref可以操作表单或样式 组件

在react把方法传过去,通过props可以访问
表单要变成受控表单
 要绑定onChange
value是用e.target.value
checkedbox value不一样   
select 是用其他的
onKeyUp大写事件名
keyCode 
keyHandle(e){
if(e.KeyCode==13){
var arr=this.state.list
arr.push(id:Date.now(),label:task)
this.setState({
    sportArr:arr
    task:' '
})
}
}

状态提升
2个数据共享,在父组件中存储
flux
状态提升
props是管理状态
方法是render同级
自定义事件
 
react处理事件 
状态提升  父子组件的通信
父组件向子组件通信通过props
子组件向父组件通信,通过自定义事件
在类组件的时候,使用构造函数中,state状态,定义方法改变setState中的数据
// 引入子组件 他们暴露的方式是以对象的方式,所以我们必须要引对象的方式引入
import { Child1, Child2 }  from  '@/components'
export default class extends React.Component{
    constructor(props){
        super(props)
        this.state={
            role:'管理员'
        }
    }
    changeRole(){
       // let { role } =this.state 错,这里不需要解构出来
        this.setState({
          role:'用户'
        })
    }
    childFn(arg){
        console.log('父')
        this.setState({
           role:arg  // 接收子组件传过来的数据,并发生改数据 
        })
    }
    render(){
        let {role } = this.state
        return(
            // 定义的数据,传给子组件  事件,传一个自定义事件,子组件通过props获取参数和事件 onRoleChange自定义事件
         <Child1 role={role} onRoleChange={this.childFn.bind(this)}></Child1>  在组件绑定自定义事件
         <Child2 role={role} onRoleChange={this.childFn.bind(this)}></Child2>
         <button onClick={this.changeRole.bind(this)}>点击状态改变</button>
        )
    }
}






child1 
在子组件中获取它的定义的属性 通过this.state.props
import React from 'react'
export default class extends React.Component{
    constructor(props){
        super(props)
    }
    child1click(){
        // this.$emit('onRoleChange','传过去的参数') //调用父组件传过来的自定义事件 
        //相当于vue中的,this.$emit() 触发父组件的自定义事件的名字
         this.props.onRoleChange('ceo') //  在父组件中去接收,传过来的事件,childFn在父组件的方法中,接收子组件传过去的参数
    }
    render(){
        let { role } = this.props
        return(
            // 定义的数据,传给子组件
         <div>
           <h3>子组件一</h3>
           <h3> 
               {role}共享
               子组件  
               // 点击该变子组件,子组件二的数据,也发生改变
               <button onClick={this.child1click.bind(this)}}>change改变</button>  点击改变管理员,并且改变子组件
           </h3>
         </div>
        )
    }
}在



child2
import React from 'react'
export default class extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        let { role } = this.props
        return(
            // 定义的数据,传给子组件
         <div>
              <h3>子组件二</h3> 
              <h3> {role}</h3>
              <button onClick={this.props.onRoleChange.bind(this'正常用户')}></button>
              // 箭头函数的写方法
              //  {} 大括号是语句,写法是错误的
              //<button onClick={()=>{this.props.onRoleChange('正常用户')}}></button>
               <button onClick={()=>this.props.onRoleChange('正常用户')}></button>
          </div>
        )
    }
}



在react组件的复用用组合,而不是继承
继承,代码的复用

组件的嵌套

不需要state,就是要无状态组件,节省性能
scss是文件的后最名


面试题
组件的复用是用组合思想  排列组合 


button 按钮的复用

react
声命周期
在constructor(props)
//不能写其他的代码
不能使用 this.setState
this.state={
    msg:this.props
}

}



// 开启定时器 调接口开启长连接
componentDidMount()  相当于mounted dom 准备就绪,动态数据化完成
componentwillMount()    相当于beforemounted 少用

页面初始化的几个钩子函数 
con
static getDer
render
componentDidMount()  

更新阶段  性能优化  diff运算的开关
diff虚拟dom对比,找到不同的差 异进行对比
shoildcomponentUpdate 更新改变state触发  要return true
return false不更新 diff算法不起作用

getSnapshotBeforeUpdate() 这个生命周期要和componentDidMount(), 而且要return null 要返回对象

卸载阶段	
componentWillUnmount()  beforeDestory    清除定时器 关闭长连接 

// 很少使用

 React是单向数据流,

day03

在render中返回一个根元素
render(
 	return(
   )
)


文档碎片中返回多个根元素
无状态组件
function QfWB(){
    return (
        <div><h3>dialog</h3></div>
    )
}



抛出多个组件
render(){
      <React.Fragment>
           <QfWB></QfWB>
       </React.Fragment>
}<>
</>



vue怎么集成路径vuex
app.js是最大的根组件

参考react文档


上下文有多个

高级组件
公共组件的复用
高级组件就是一个纯函数
render 就纯函数,唯一输入唯一的输出(结果)
返回的就是一个高级组件

// 函数组件 (无状态组件)
接受props
function Model(props){

}

return (){
{/* jsx,单一根节点   */}
}

this.props.hand
this.props.hand()

高级组件,包裹公共的东西,对组件的修饰,注入公共的api   第一种写法  hoc(函数)  第二种写法 @hoc
this.props.hand
高级组件和组合组件不同

高级组件(容器组件):对uI组件的进行包装或修饰  @hoc修饰 作用是
用改变类的行为,修饰方法
UI组件

propType
对子组件类性的检测
cnpm i prop-types   -S

react把混入移出了

hook是在react16.5出现
Hooks 它是一组函数api

自定义hooks
hooks有下面的钩子
useState 相当于state   let [ count,setCount   ] =useState(20)
function countChange (){
      setCount(count+1)
}
useEffect :(副作用)开启长连接,dom的操作。定时器 调接口
相当于三个生命周期   componentDidMount (Mounted)    componentDidUpdated  (Updated)   componentWilldDestory(Destory) 可以做dom的
useContent
useRef
自定义hooks
解决问题:  (class)组件,性能没有函数组件好  函数组件(无状态组件,性能高)
// Hooks  让函数组件,可以拥有state,声明周期的特性 上下文
hooks提供api,解决问题
// 定义纯组件,要引入import 
function Model(props){  // 传props
    // 无组件没有this,
    function clickHandle(){
       console.log('1')
    } 
    return(
        <div onClick={clickHandle}></div>
    )
}


react-router-dom

组件的路由是自己手动写

生成侧边导航

动态绑定,在vue中不能有:
activeclassName是react中添加高亮的
<NavLink to='/fram' activeclassName='red'></NavLink >
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页