React笔记

react学习笔记

基础篇

1、条件渲染

const isLoading = true;
const loadData = () => {
  if (isLoading) {
    return <div> loading...</div>;
  }
  return <div>数据加载完成。。。</div>;
};
const loadData2 = () => {
   
 return isLoading?(<div> loading...</div>):(<div>数据加载完成。。。</div>)
};

const loadData3 = () => {
   
  return isLoading&&(<div> loading...</div>)
 };
const title = (
  <div>
    <h1>条件渲染</h1>
    {loadData3()}
  </div>
);

2、列表渲染

vue 的思想就是 v-for

这里值得提一下的是,key不建议使用 index (索引),尽量使用不可变的数据

import React from "react";
import ReactDom from "react-dom";
//  const title = React.createElement('h1', null, 'Hello React !!!!')
const title = (
  <h1>
    {" "}
    hello jsx <span id="span"> span </span>
  </h1>
);
const songs = [{ id: 1, name: "向阳花"},{id: 2, name: "鼓楼"},{id: 3, name: "梵高先生" }];
const list=(<div> {songs.map((item,index)=><div key={index}>{item.name}</div>)}</div>)
ReactDom.render(title, document.getElementById("root"));
ReactDom.render(list,document.getElementById("span"))

3、样式处理

index.css

.title{
  text-align: center;
}


const blue='blue'
const title = (
  <div className="title" style={{'color':'red','background-color':blue}}>
   样式处理
  </div>
);

ReactDom.render(title, document.getElementById("root"));

4、组件

1、函数组件

//大写字母开头,必须有返回值
const Hello=()=>{
  return(<div>这是一个组件 </div>)
}
ReactDom.render(<Hello/>, document.getElementById("root"));

2、类组件

/**
 * 继承  React.Component,从而使用父类的属性及其方法
 * 必须实现render ,并且有返回值
 */
class Hello extends React.Component{
  render(){
    return (<div>Hello class Component</div>)
  }
}
ReactDom.render(<Hello/>, document.getElementById("root"));

3、抽离单独的js文件

component/Hello.js

import React from "react";
class Hello extends React.Component {
  render() {
    return <div> Hello class Component </div>;
  }
}

export default Hello;

import Hello from './component/Hello'
ReactDom.render(<Hello/>, document.getElementById("root"));

4、有无状态组件

无状态组件:函数组件,只负责数据展示

有状态组件:类组件,负责更新UI

状态:state,即数据

5、state与setState()

class Hello extends React.Component {
  handdleClik = () => {
    this.setState({
      count:this.state.count+1
    })
   this.state.count++
  };
  state= { count: 1 };
  render() {
    return (
      <div>
        {" "}
        <div onClick={this.handdleClik}>计数器:  {this.state.count}</div>
      </div>
    );
  }
}

6、this指向

1、箭头函数
  handdleClik2() {
    this.setState({
      count: this.state.count + 1,
    });
    this.state.count++;
  }
  <div onClick={() => this.handdleClik2()}>
          计数器2{this.state.count}
    </div>
2、Funtion.prototype.bind()

利用ES5中的bind方法,将事件处理程序中的 this与组件实例绑定到一起

 constructor(){
   super()
   this.state={
     count:0
   }
   this.handdleClik=this.handdleClik.bind(this)
 }

handdleClik  ()  {
    this.setState({
      count: this.state.count + 1,
    });
    this.state.count++;
  };
3、类的实例方法

5、事件处理

1、事件绑定

const handdleClik1 = () => {
  console.log("单击事件触发1");
};
class Hello extends React.Component {
  handdleClik2 = () => {
    console.log("单击事件触发2");
  };
  render() {
    return (
      <div>
        {" "}
        <div onClick={handdleClik1}>handdleClik1</div>
        <div onClick={this.handdleClik2}>handdleClik2</div>
      </div>
    );
  }
}

2、事件对象(合成事件)

  handdleClik3 = (e) => {
    //阻止浏览器默认行为
    e.preventDefault();
    console.log("单击事件触发3");
  };

 <a href="https://www.baidu.com" onClick={this.handdleClik3}>
          handdleClik3
 </a>

3、表单处理

class Hello extends React.Component {
  handleOnChange = (e) => {
    this.setState({
      text: e.target.value,
    });
  };
  handleOnChange2 = (e) => {
    this.setState({
      context: e.target.value,
    });
  };
  cityChange = (e) => {
    this.setState({
      city: e.target.value,
    });
  };
  isCheckedChange = (e) => {
    this.setState({
      isChecked: e.target.checked,
    });
  };

  state = { text: "1", context: "", city: "bj", isChecked: false };
  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.text}
          onChange={this.handleOnChange}
        />
        <br />
        <textarea
          value={this.state.context}
          onChange={this.handleOnChange2}
        ></textarea>
        <br />
        <select value={this.state.city} onChange={this.cityChange}>
          <option value="sh">上海</option>
          <option value="bj">北京</option>
          <option value="gz">广州</option>
        </select>
        <br />
        <input
          type="checkbox"
          checked={this.state.isChecked}
          onChange={this.isCheckedChange}
        />
      </div>
    );
  }
}

4、多表单元素的事件处理

class MoreInput extends React.Component {
  handleOnChange = (e) => {
    const target = e.target;
    const value =
      e.target.type === "checkbox" ? e.target.checked : e.target.value;
    const name = target.name;
    this.setState({
      [name]: value,
    });
  };
  state = { text: "1", context: "", city: "bj", isChecked: false };
  render() {
    return (
      <div>
        <input
          type="text"
          name="text"
          value={this.state.text}
          onChange={this.handleOnChange}
        />
        <br />
        <textarea
          value={this.state.context}
          onChange={this.handleOnChange}
          name="context"
        ></textarea>
        <br />
        <select
          value={this.state.city}
          onChange={this.handleOnChange}
          name="city"
        >
          <option value="sh">上海</option>
          <option value="bj">北京</option>
          <option value="gz">广州</option>
        </select>
        <br />
        <input
          type="checkbox"
          checked={this.state.isChecked}
          onChange={this.handleOnChange}
          name="isChecked"
        />
      </div>
    );
  }
}

5、非受控组件

class Uncontrolled extends React.Component {
    constructor() {
        super()

        //创建ref
        this.txtRef = React.createRef()
    }
    getTxtRef = () => {
        console.log("当前的值是:", this.txtRef.current.value)
    }

    render(){
        return (
            <div>
                <input type="text" ref={this.txtRef}></input>
                <button onClick={this.getTxtRef}>获取文本框的值</button>
            </div>
        )
    }
}

进阶篇

1、组件传参

1、props示例

export default class PropsTest extends React.Component {
    render(){
        console.log(this.props)
        return(
            <div>接受到的数据:{this.props.name} {this.props.tag}</div>
        )
    }
}

 <PropsTest
    name="无限"
    age={age}
    color={[1, 2, 3, 4]}
    fn={() => {
      console.log("hello");
    }}
    tag={<p>哈哈哈哈</p>}
  />

2、父组件传递子组件

Child.js
import React from "react";
export default class Child extends React.Component {
  render() {
    return <div>我是Child,接收到父亲的消息: {this.props.name}</div>;
  }
}

Parent.js
import React from "react";
import Child from "./Child";
export default class Parent extends React.Component {
  render() {
    return (
      <div>
        parent
        <br /> <Child name={"我是你爹"}></Child>
      </div>
    );
  }
}

3、子组件传递父组件

Child.js
export default class Child extends React.Component {
  state = { count: 100 };
  getMsg = () => {
    this.props.getMsg(`给我零花钱${this.state.count}`);
  };
  render() {
    return (
      <div>
        我是Child,接收到父亲的消息: {this.props.name}
        <br />
        <button onClick={this.getMsg}>向我爹要零花钱</button>
      </div>
    );
  }
}

Parent.js
export default class Parent extends React.Component {
  state = { count: 0 };
  getChildMsg = (data) => {
    console.log("收到兔崽子的消息", data);
    this.setState({
      count: data,
    });
  };
  render() {
    return (
      <div>
        parent
        <br /> <Child name={"我是你爹"} getMsg={this.getChildMsg}></Child>
        <br />
        <div>我儿子向我要多少钱:{this.state.count}</div>
      </div>
    );
  }
}

4、兄弟组件之间的传递

Brother.js
export default class Brother extends React.Component {
    getMsg = () => {
        this.props.getMsg('微笑拥抱每一天,做像向日葵般温暖的女子');
      };
  render() {
    return (
      <div onClick={this.getMsg}>
        我是Brother,发送给妹妹的消息
        <br />
      </div>
    );
  }
}
Sister.js
import React from "react";
export default class Sister extends React.Component {
  render() {
    return (
      <div>
        我是Sister,接收到哥哥的消息: {this.props.msg}
        <br />
      </div>
    );
  }
}

parent.js
export default class Parent extends React.Component {
  state = { count: 0, childMsg: "" };
  getChildMsg = (data) => {
    console.log("收到兔崽子们之间的消息", data);
    this.setState({ childMsg: data });
  };
  render() {
    return (
      <div>
        <Sister msg={this.state.childMsg}/>
        <Borther getMsg={this.getChildMsg} />
      </div>
    );
  }
}

5、Context(跨组件传递)

//创建两个组件
const { Provider, Consumer } = React.createContext();
class App extends React.Component {
  render() {
    return (
      <div>
        <Provider value="pink">
          {" "}
          <Node />
        </Provider>
      </div>
    );
  }
}
const Node = () => {
  return (
    <div className="node">
      <SubNode />
    </div>
  );
};

const SubNode = () => {
  return (
    <div className="SubNode">
      <Child />
    </div>
  );
};
const Child = (props) => {
  return (
    <div className="child">
      <Consumer>{(data) => <span>我是子节点 ---- {data}</span>}</Consumer>
    </div>
  );
};

6、props深入

1、children
class App extends React.Component {
  render() {
    this.props.children()

    return (
      <div>
        子节点:
        <br />
        {/* {this.props.children} */}
        <br />
        <Test></Test>
      </div>
    );
  }
}
const Test = () => {
  return <button>button</button>;
};
ReactDom.render(
  <div>
    <App>
      {/* 我是子节点{" "} */}
      {() => {
        console.log("这个是一个子节点的函数打印体");
      }}
    </App>
  </div>,
  document.getElementById("root")
);
2、props校验

默认的props没有类型约定,开发中容易出现一些错误并且无法定位,使用第三方的包,可以添加类型判断

npm i -S prop-types
import PropTypes from 'prop-types';
App.prototype={
  color:PropTypes.array
}
约束规则

常见类型:

  • array、bool、func、number、object、string

  • 元素类型:

  • element

  • 必填项:

  • isRequired

  • 特定结构的对象:shape({})

3、props默认值
App.defaultProps={
  num:10
}
 <App num={20}>  </App>

2、生命周期

1、创建时(挂载阶段)

执行顺序: constructor ==> render ==> componentDidMount

钩子函数触发时机作用
constructor创建时,最先执行初始化state,为事件处理绑定this
render每次渲染触发渲染UI,不能调用setState()
componentDidMount组件挂载(完成DOM渲染)后发送网络请求,DOM操作
class App extends React.Component {
  constructor(props) {
    super(props);
    console.log("生命周期:constructor");
  }
  render() {
    console.log("生命周期:render");
    return (
      <div>
        <h1> 统计打豆豆的次数</h1>
        <button>打豆豆</button>
      </div>
    );
  }
  componentDidMount() {
    console.log("生命周期:componentDidMount");
  }
}

2、更新时(更新阶段)

执行时机 setState(),forceUpdate(),组件接收到新的props

执行顺序: render ==> componentDidUpdate

钩子函数触发时机作用
render每次渲染触发渲染UI,与挂载阶段是同一个
componentDidUpdate组件更新,完成DOM渲染之后发送网络请求,DOM操作
class Child extends React.Component {
  render() {
    return <div> 我是子组件</div>;
  }
  componentDidUpdate(prevProps) {
    console.log("生命周期:componentDidUpdate");
    console.log("old:", prevProps.count, "new", this.props.count);
  }
}

class App extends React.Component {
  
  addCount = () => {
    this.setState({
      count: this.state.count + 1,
    });
  };

  state = { count: 0 };
  render() {

    return (
      <div>
        <h1> 统计打豆豆的次数{this.state.count}</h1>
        <button onClick={this.addCount}>打豆豆</button>
        <Child count={this.state.count}></Child>
      </div>
    );
  }
}

3、卸载时(卸载阶段)

组件从页面消失

钩子函数触发时机作用
componentWillUnmount组件卸载,从页面消失执行清理工作,比如计时器等
//子组件
componentDidMount() {
    console.log("生命周期:componentDidMount");
    this. time = setInterval(() => {
      console.log("定时器触发~~");
    }, 1000);
  }

  componentWillUnmount() {
    console.log("死了。。。");
    clearInterval(this.time)
}
//父组件
 render() {
    console.log("生命周期:render");
    return (
      <div>
        {this.state.count > 3 ? (
          <p>别打了,已经死了 </p>
        ) : (
          <Child count={this.state.count}></Child>
        )}

        <h1> 统计打豆豆的次数{this.state.count}</h1>
        <button onClick={this.addCount}>打豆豆</button>
      </div>
    );
  }

3、render-props

1、render-props模式、及其组件复用

class Mouse extends React.Component {
  state = { x: 0, y: 0 };
  handleMouseMover = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY,
    });
  };
  render() {
    return this.props.render(this.state);
  }
  componentDidMount() {
    window.addEventListener("mousemove", this.handleMouseMover);
  }
}
class App extends React.Component {
  render() {
    return (
      <div>
        <Mouse
          render={(mouse) => {
            return (
              <p>
                鼠标位置 x:{mouse.x} y:{mouse.y}
              </p>
            );
          }}
        ></Mouse>
        <Mouse
          render={(mouse) => {
            return (
              <img
                src="http://picsum.photos/50/50?random=1"
                style={{
                  position: "absolute",
                  left: mouse.x - 25,
                  top: mouse.y - 25,
                }}
              />
            );
          }}
        ></Mouse>
      </div>
    );
  }
}

2、children替换render属性

class Mouse extends React.Component {
  state = { x: 0, y: 0 };
  handleMouseMover = (e) => {
    this.setState({
      x: e.clientX,
      y: e.clientY,
    });
  };
  render() {
    return this.props.children(this.state);
  }
  componentDidMount() {
    window.addEventListener("mousemove", this.handleMouseMover);
  }
}
class App extends React.Component {
  render() {
    return (
      <div>
        <Mouse>
          {(mouse) => {
            return (
              <p>
                鼠标位置 x:{mouse.x} y:{mouse.y}
              </p>
            );
          }}
        </Mouse>
        <Mouse>
          {(mouse) => {
            return (
              <img
                src="http://picsum.photos/50/50?random=1"
                style={{
                  position: "absolute",
                  left: mouse.x - 25,
                  top: mouse.y - 25,
                }}
              />
            );
          }}
        </Mouse>
      </div>
    );
  }
}

4、高阶组件

1、基本使用

function WithMouse(WrappedComponent) {
  class Mouse extends React.Component {
    state = {
      x: 0,
      y: 0,
    };
    handleMouseMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY,
      });
    };
    componentDidMount() {
      window.addEventListener("mousemove", this.handleMouseMove);
    }

    render() {
      return <WrappedComponent {...this.state}></WrappedComponent>;
    }
  }

  return Mouse;
}
const Position = (props) => {
  return (
    <p>
      x:{props.x}y:{props.y}
    </p>
  );
};
const MousePosition=WithMouse(Position)


ReactDom.render(
  <div>
    <MousePosition></MousePosition>
  </div>,
  document.getElementById("root")
);

2、displayNmae

//获取name
function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayname || WrappedComponent.name || `Component`;
}
function WithMouse(WrappedComponent) {
  class Mouse extends React.Component {
    state = {
      x: 0,
      y: 0,
    };
    handleMouseMove = (e) => {
      this.setState({
        x: e.clientX,
        y: e.clientY,
      });
    };
    componentDidMount() {
      window.addEventListener("mousemove", this.handleMouseMove);
    }

    render() {
      return <WrappedComponent {...this.state}></WrappedComponent>;
    }
  }
  Mouse.displayname = `WithMouse${getDisplayName(WrappedComponent)}`;
  return Mouse;
}

3、传递props

  render() {
      return <WrappedComponent {...this.state}  {...this.props}></WrappedComponent>;
    }

5、路由

1、基本使用

import { BrowserRouter as Router, Route, Link } from "react-router-dom";

const First = () => {
  return <div>第一个页面</div>;
};
class App extends React.Component {
  render() {
    return (
      <Router>
        <div>App</div>
        {/* 指定路由入口 */}
        <Link to="/first">页面一</Link>
            {/* 指定路由出口 */}
        <Route path="/first" component={First}></Route>
      </Router>
    );
  }
}

2、常用组件说明

  • Router组件:包裹整个应用,一个React应用只需要一个
  • 两种常用的Router: HashRouter(#)和BrowserRouter
  • HashRouter:使用URL的哈希值实现 127.0.0.1:3000/#/frist
  • BrowserRouter:使用H5的history API实现 127.0.0.1:3000/frist
  • Like:指定导航连接
  • Route :指定路由展示组件

3、编程式导航(js实现路由切换)

class Login extends React.Component {
  toHome = () => {
    this.props.history.push("/home");
  };
  render() {
    return (
      <div>
        {" "}
        登录页面
        <br />
        <button onClick={this.toHome}>登录</button>
      </div>
    );
  }
}
const Home = (props) => {
  const goBack = () => {
    props.history.go(-1);
  };
  return (
    <div>
      {" "}
      首页
      <br />
      <button onClick={goBack}>返回登录页面</button>{" "}
    </div>
  );
};
class App extends React.Component {
  render() {
    return (
      <Router>
        <div>
          <Link to="/login"> 登录 </Link>
          <Route path="/login" component={Login}></Route>
          <Route path="/home" component={Home}></Route>
        </div>
      </Router>
    );
  }
}

4、默认路由

  <Route path="/" component={Home}></Route>

5、withRouter

在非路由组件获取当前路由path时需要这个组件处理

/**
 * 包装非路由组件,
 * 返回新的组件
 * 新的组件包含三个属性   history,location,match
 */

//获取当前的路由path
     const path=this.props.location.pathname
export default withRouter(leftNav);

6、匹配模式

1、模糊匹配

​ 类似与vue-router的子路由与父路由

const A = () => {
  return <div>页面A</div>;
};
const AC1 = () => {
  return <div>页面A的子页面1</div>;
};
const AC2 = () => {
  return <div>页面A的子页面2</div>;
};
class App extends React.Component {
  render() {
    return (
      <Router>
        <div>
          <Link to="/a"> to页面A </Link>
          <Link to="/a/ac1">to页面A的子页面1</Link>{" "}
          <Link to="/a/ac2">to页面A的子页面2</Link>
          <Route path="/a" component={A}></Route>
          <Route path="/a/ac1" component={AC1}></Route>{" "}
          <Route path="/a/ac2" component={AC2}></Route>
        </div>
      </Router>
    );
  }
}
2、精准路由

只显示子路由不显示父路由

//添加关键字 exact
 <Route path="/a" exact component={A}></Route>

7、路由守卫

首先明确,在之前的版本中,React Router 也提供了类似的 onEnter 钩子,但在 React Router 4.0 版本中,取消了这个方法。React Router 4.0 采用了声明式的组件,路由即组件,要实现路由守卫功能,就得我们自己去写了。

BeforeEach.jsx

import { Route, Redirect } from "react-router-dom";
import React, { Component } from "react";
class BeforeEach extends Component {
  render() {
    const { location, config } = this.props;
    const { pathname } = location;
    const isLogin = true;
    console.log(pathname);
    // 如果该路由不用进行权限校验,登录状态下登陆页除外
    // 因为登陆后,无法跳转到登陆页
    // 这部分代码,是为了在非登陆状态下,访问不需要权限校验的路由
    const targetRouterConfig = config.find((v) => v.path === pathname);
    if (targetRouterConfig && !targetRouterConfig.auth && !isLogin) {
      const { component } = targetRouterConfig;
      return <Route exact path={pathname} component={component} />;
    }

    if (isLogin) {
      // 如果是登陆状态,想要跳转到登陆,重定向到主页
      if (pathname === "/login") {
        return <Redirect to="/" />;
      } else {
        // 如果路由合法,就跳转到相应的路由
        if (targetRouterConfig) {
          return (
            <Route path={pathname} component={targetRouterConfig.component} />
          );
        } else {
          // 如果路由不合法,重定向到 404 页面
          return <Redirect to="/404" />;
        }
      }
    } else {
      // 非登陆状态下,当路由合法时且需要权限校验时,跳转到登陆页面,要求登陆
      if (targetRouterConfig && targetRouterConfig.auth) {
        return <Redirect to="/login" />;
      } else {
        // 非登陆状态下,路由不合法时,重定向至 404
        return <Redirect to="/404" />;
      }
    }
  }
}
export default BeforeEach;

routerCconfig.js

 import User from "../pages/user"; //暂时担任404的任务
 import Home from "../pages/home";
 import Login from "../pages/login";
 export const routerConfig = [{
     path: '/',
     component: Home,
     auth: true,
 }, {
     path: '/home',
     component: Home,
     auth: true,
 }, {
     path: '/login',
     component: Login,
 }, {
     path: '/404',
     component: User
 }];

App.jsx

   <Switch>
       <BeforeEach config={routerConfig}></BeforeEach>
    </Switch>	

6、Redux

1、基本使用

count.jsx

import React from "react";
import store from "../../store/index";
import {createIncrementAction} from '../../store/count_action'
export default class Count extends React.Component {
  state = {
    wind: "北风6级",
  };

  increment = () => {
      store.dispatch(createIncrementAction(1));
   };
  decrement = () => {
    const action = { type: "decrement", data: 1 };
    store.dispatch(action);

   };
  render() {
    return (
      <div>
        <h2>当前求和:{store.getState()}</h2>
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    );
  }
}

store 文件夹

constant.js

export const INCREMENT = 'increment'

count_action.js

import {INCREMENT} from './constant'
//用来创建action函数
export const createIncrementAction = value => ({
    type: INCREMENT,
    data: value
})

count.js

export default function countReducer(preState = 0, action) {
    const {
        type,
        data
    } = action

    switch (type) {
        case 'increment':
            return preState + data
        case 'decrement':
            return preState - data
        default: //初始化
            return preState
    }

}

index.js

import {createStore} from 'redux'
import countReducer from './count'
const Store =createStore(countReducer)

export default Store

2、 react-redux

src\container\count\index.jsx

//ui组件的容器组件,用于UI连接Redux
import CountUi from '../../components/count/count'
import {connect} from 'react-redux'
import store from '../../store/index'

function a(){
     return {count:store.getState()}
}
const CountContainer=connect(a)(CountUi)

export default CountContainer

src\components\count\count.jsx

import React from "react";
export default class Count extends React.Component {
  state = {
    wind: "北风6级",
  };

  increment = () => {};
  decrement = () => {};
  render() {
    return (
      <div>
        <h2>当前求和:{this.props.count}</h2> 
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </div>
    );
  }
}

src\index.js

import React from "react";
import ReactDOM from "react-dom";

//import Count from "./components/count/count";
import Count from './container/count/index'
import store from "./store/index";
//当状态发生变化,必定调用整个方法
store.subscribe(() => {
  ReactDOM.render(
    <div>
      app
      <br />
      <Count store={store}></Count>
    </div>,
    document.getElementById("root")
  );
});
ReactDOM.render(
  <div>
    app
    <br />
    <Count store={store}></Count>
  </div>,
  document.getElementById("root")
);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值