• react(二)


    react(二)

    一、create-react-app(脚手架)

    是Facebook官方推出的一个款react脚手架

    1.1 环境

    需要安装node 升级到最新版本

    1.2 安装

    npm install -g create-react-app
    create-react-app --version
    cd 指定目录
    create-react-app 项目名
    npm start
    

    1.3 目录结构

    my-app/
      README.md
      node_modules/
      package.json
      .gitignore
      public/
        favicon.ico
        index.html
        manifest.json
      src/
        App.css
        App.js
        App.test.js
        index.css
        index.js
        logo.svg
    

    manifest.json 指定了开始页面 index.html,一切的开始都从这里开始,所以这个是代码执行的源头。

    二、传参

    2.1 正向传参

    // 父组件
    // 传递参数text:<Son text="你好"/>
    import React, {Component} from 'react';
    import Son from "./son"
    class Parent extends Component {
        render() {
            return (
                <div>
                    <Son text="你好"/>
                </div>
            );
        }
    }
    export default Parent;
    
    // 子组件
    // 接受参数text:this.props.text
    import React, {Component} from 'react';
    class Son extends Component {
        render() {
            return (
                <div>
                    son--{this.props.text}
                </div>
            );
        }
    }
    
    export default Son;
    

    2.2 反向传参

    // 父组件
    // 接受fufun,修改自身setState.text为传递过来的text
    import React, {Component} from 'react';
    import Son from "./son"
    class Parent extends Component {
        constructor(props){
            super(props)
            this.state={
                text:"我是parent默认值",
            }
        }
        dataFun=(text)=>{
            this.setState({
                text:text
            })
        }
        render() {
            return (
                <div>
                    parent---{this.state.text}
                    <Son text="你好" fufun={this.dataFun}/>
                </div>
            );
        }
    }
    export default Parent;
    
    // 子组件
    // 点击事件传递参数fufun,携带数据sonText:
    // 方式一:
    // this.props.fufun.bind(this,this.state.sonText)
    // 方式二:
    // ()=>{this.props.fufun(this.state.sonText)}
    import React, {Component} from 'react';
    class Son extends Component {
        constructor(props){
            super(props)
            this.state={
                num:123,
                sonText:"son数据"
            }
        }
        render() {
            return (
                <div>
                    <button onClick={this.props.fufun.bind(this,this.state.sonText)}>点我将数据发送给parent</button>
                    <button onClick={()=>{this.props.fufun(this.state.sonText)}}>点我将数据发送给parent</button>
                </div>
            );
        }
    }
    
    export default Son;
    

    2.3 同级传参:pubsub-js

    // 安装
    cnpm install --save pubsub-js
    
    import Pubsub from "pubsub-js"
    
    // 同级传参数
    Pubsub.Pubsub.publish("evt",this.state.num)
    // 同级取参数
    Pubsub.subscribe("evt",(msg,data)=>{
                console.log("phone",data)
            })
    

    三、数据请求与json-server

    # json-server:模拟数据
    npm install json-server -g
    # axios:数据请求
    npm install --save axios
    # 项目根目录新建mook目录,创建data.json,写入json数据
    cd mook
    json-server data.json --port 4000
    # 页面中引用data.json
    
    import React, {Component,Fragment} from 'react';
    import axios from "axios"
    class Home extends Component {
        constructor(props){
            super(props)
            this.state={
                arr:[]
            }
        }
        componentDidMount() {
            this.ajaxfun()
        }
        ajaxfun=()=>{
            axios.get("http://localhost:4000/arr").then((ok)=>{
                console.log(ok)
                this.setState({
                    arr:ok.data
                })
            })
        }
        render() {
            return (
                <Fragment>
                    {this.state.arr.map((v,i)=>{
                        return <p key={i}>{v.name}</p>
                    })}
                </Fragment>
            );
        }
    }
    
    export default Home;
    

    四、跨域

    4.1 正向代理--开发环境

    一个位于客户端和目标服务器之间的代理服务器,为了获取目标服务器的内容,客户端向代理服务器发送一个请求,代理服务器帮助我们去目标服务器里获取数据并且返给我们。

    4.2 反向代理--上线环境

    可以通过代理服务器来接受网络上的请求连接,然后将这个请求转发给内部的网络服务器,并且把这个服务器上得到的数据返回给请求的客户端。

    4.3 模拟请求真实的网络接口

    中国天气网中的数据

    # 首先修改文件 node_modules/react-scripts/config/webpackDevServer.config.js
    # 找到proxy,修改变量
    proxy:{
    	"/api":{
    		target:"http://www.weather.com.cn/data/cityinfo/",
    		changeOrigin:true,
    		"pathRewrite":{
    			"^/api":"/"
    		}
    	}
    }
    
    import React, {Component} from 'react';
    import axios from 'axios'
    
    class Weather extends Component {
        componentDidMount() {
            axios.get("/api/101320101.html").then((ok)=>{
                console.log(ok)
            })
        }
    
        render() {
            return (
                <div>
    
                </div>
            );
        }
    }
    
    export default Weather;
    

    五、路由

    根据url的不同来切换对应的组件,实现spa(单页面应用),在页面切换的时候不会刷新,更加接近原生体验

    学习版本:v5版本

    5.1 下载路由

    # 下载路由
    npm install --save react-router-dom --功能多
    npm install --save react-router    -- 核心包
    

    5.2 两种路由

    react-router:提供了核心的API

    react-router-dom:提供了更多的选项

    5.3 路由模式

    hash模式 -- HashRouter

    • hash模式带#号,刷新的时候页面不会丢失

    browser -- BrowserRouter

    • 历史记录模式,没有#号,他是通过历史记录api来进行路由切换的,刷新会丢失,本地模式不会

    5.4 引用路由模块

    // 找到index.js
    // 引入BrowserRouter,包裹<App />
    import {BrowserRouter,HashRouter} from "react-router-dom"
    

    5.5 路由模式包裹根组件

    # BrowserRouter
    ReactDOM.render(
      <React.StrictMode>
        <BrowserRouter>
        <App />
        </BrowserRouter>
      </React.StrictMode>,
      document.getElementById('root')
    );
    # HashRouter
    ReactDOM.render(
      <React.StrictMode>
        <HashRouter>
        <App />
        </HashRouter>
      </React.StrictMode>,
      document.getElementById('root')
    );
    

    5.6 使用

    // App.js
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    // 引入组件
    import Home from "./components/Home"
    import Parent from "./components/parent"
    import Son from "./components/Son"
    import Weather from "./components/Weather";
    // 引入路由
    import {Route} from "react-router-dom"
    
    // 地址连接时
    // BrowserRouter
    // http://localhost:3000/son
    
    // HashRouter
    // http://localhost:3000/#/son
    
    function App() {
      return (
            <div className="App">
              <header className="App-header">
                  // 配置路由
                  <Route path="/home" component={Home}/>
                  <Route path="/parent" component={parent}/>
                  <Route path="/son" component={Son}/>
                  <Route path="/weather" component={Weather}/>
              </header>
            </div>
      );
    }
    
    export default App;
    
    

    5.7 路由导航

    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    
    import Home from "./components/Home"
    import Parent from "./components/parent"
    import Weather from "./components/Weather";
    import Son from "./components/son";
    // 多配置一个Link 或者 NavLink
    import {Route,Link,NavLink} from "react-router-dom"
    
    
    function App() {
      return (
            <div className="App">
              <header className="App-header">
                  <div>
                      // 使用link标签
                      <Link to="/home">点我去home</Link>
                      <Link to="/parent">点我去parent</Link>
                      <Link to="/son">点我去son</Link>
                      <Link to="/weather">点我去weather</Link>
                  </div>
                  <div>
                      // NavLink:声明式导航
                      // 使用时添加了class="active"
                      // 可以选中的导航动态设置样式
                      <NavLink to="/home">点我去home</NavLink>
                      <NavLink to="/parent">点我去parent</NavLink>
                      <NavLink to="/son">点我去son</Link>
                      <NavLink to="/weather">点我去weather</NavLink>
                  </div>
                  <Route path="/home" component={Home}/>
                  <Route path="/parent" component={Parent}/>
                  <Route path="/son" component={Son}/>
                  <Route path="/weather" component={Weather}/>
              </header>
            </div>
      );
    }
    export default App;
    
    

    5.8 exact

    如果path是'/',会匹配全路径,对应的路由每次都会匹配到。为了防止这种效果没加入exact。

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

    5.9 Switch

    唯一渲染

    import {Route,Link,NavLink,Switch} from "react-router-dom"
    <Switch>
        <Route path="/home" component={Home}/>
        <Route path="/home" component={Home}/>
    </Switch>
    

    5.10 重定向

    import {Route,Link,NavLink,Switch,Redirect} from "react-router-dom"
    <Redirect><Route from="/" to="/home" exact/></Redirect>
    

    5.11 二级路由

    # 目录components下新建home目录,home下新建HomeA.js,然后rcc
    # 目录components下新建home目录,home下新建HomeB.js,然后rcc
    # home.js
    import React, {Component} from 'react';
    import {Route,NavLink} from "react-router-dom"
    
    import HomeA from "../home/HomeA"
    import HomeB from "../home/HomeB"
    
    class Home extends Component {
        render() {
            return (
                <NavLink to="/home/homeA">HomeA</NavLink>
                <NavLink to="/home/homeB">homeB</NavLink>
               <Route path="/home/homeA" component={HomeA}/>
               <Route path="/home/homeB" component={HomeB}/>
            );
        }
    }
    export default Home;
    

    5.12 withRouter(高阶组件)

    不是路由切换的组件也具有路由的三个属性(location,match,history)

    高阶组件(HOC)

    参数是一个组件,同时返回的也是一个组件,这类组件我们成为高阶组件。

    // 引入
    import {Route,withRouter} from "react-router-dom"
    // 包裹
    export default withRouter(App);
    

    路由式导航

    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    
    import Home from "./components/Home"
    import Parent from "./components/parent"
    import Weather from "./components/Weather";
    import Son from "./components/son";
    
    import {Route,NavLink,withRouter} from "react-router-dom"
    function App() {
       
       // history.listen((link)=>{
       // 	Link.pathname 切换路径
       // })
       props.history.listen((link)=>{
           console.log(link)
       })
        
       console.log(props)
        
      return (
            <div className="App">
              <header className="App-header">
                  <div>
                      // 声明式导航
                      <NavLink to="/home">点我去home</NavLink>
                      <NavLink to="/parent">点我去parent</NavLink>
                      <NavLink to="/son">点我去son</NavLink>
                      <NavLink to="/weather">点我去weather</NavLink>
                      // 编程式导航
                      <button onClick={()=>{props.history.push("/home")}}>点我去home</button>
                      <button onClick={()=>{props.history.push("/parent")}}>点我去parent</button>
                      <button onClick={()=>{props.history.push("/son")}}>点我去son</button>
                      <button onClick={()=>{props.history.push("/weather")}}>点我去weather</button>
                  </div>
                  <Route path="/home" component={Home}/>
                  <Route path="/parent" component={Parent}/>
                  <Route path="/son" component={Son}/>
                  <Route path="/weather" component={Weather}/>
              </header>
            </div>
      );
    }
    export default withRouter(App);
    

    路由式传参

    params方式进行传参

    1、需要在路由规则中设置传递的接收参数。形如::xxx

    2、发送参数。直接在跳转路径后进行编写

    3、 接收参数。props.match.params.参数名

    4、优势。刷新地址,参数依然存在。

    5、缺点。只能传递字符串。参数较多时,url过长变丑陋

    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    import Home from "./components/Home"
    import {Route,NavLink,withRouter} from "react-router-dom"
    function App() {
       
       // history.listen((link)=>{
       // 	Link.pathname 切换路径
       // })
       props.history.listen((link)=>{
           console.log(link)
       })
        
      return (
            <div className="App">
              <header className="App-header">
                  <div>
                      <NavLink to="/home/我是参数">点我去home</NavLink>
                  </div>
                  <Route path="/home/:id" component={Home}/>
              </header>
            </div>
      );
    }
    export default withRouter(App);
    
    import React, {Component,Fragment} from 'react';
    
    class Home extends Component {
        componentDidMount() {
            // 接收参数
            console.log(this.props.match.params.id)
        }
        render() {
            return (
     
            );
        }
    }
    
    export default Home;
    
    query方式传参

    1、不需要在路由规则中传递参数的配置

    2、直接发送数据

    3、使用this.props.location.query.xxx

    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    import Home from "./components/Home"
    import {Route,NavLink,withRouter} from "react-router-dom"
    function App() {
       
       // history.listen((link)=>{
       // 	Link.pathname 切换路径
       // })
       props.history.listen((link)=>{
           console.log(link)
       })
        
      return (
            <div className="App">
                  <div>
                      <NavLink to={{pathname:"/home",query:{name:"小明"}}}>
                                    点我去home
                      </NavLink>
                  </div>
                  <Route path="/home/:id" component={Home}/>
            </div>
      );
    }
    export default withRouter(App);
    
    import React, {Component,Fragment} from 'react';
    
    class Home extends Component {
        componentDidMount() {
            // 接收参数
            console.log(this.props.location.query.name)
        }
        render() {
            return (
     
            );
        }
    }
    
    export default Home;
    

    六、Hook

    Hook 是 React 16.7新增特性。可以让无状态组件使用状态。

    在React开发中,状态的管理必不可少。

    以前进行状态管理,需要使用类组件或者redux等来管理。

    // 引用Hook中的useState
    import React,{useState} from 'react';
    import logo from './logo.svg';
    import './App.css';
    
    // 类组件方式
    class App extends React.Component{
        constructor(props){
            super(props)
            this.state={
                text:"我是状态数据"
            }
        }
        render(){
            return (
            	<div>
                	hello --- {this.state.text}
                </div>
            )
        }
    }
    
    // 无状态组件方式
    // 可以使用Hook中的useState进行实现
    // useState定义一个状态,与类组件的状态不同,函数组件的状态可以是对象也可以是基础类型数据
    // userState返回的是一个数组。有两个元素。
    // 第一个是当前状态值,第二个是对象表明用于更改状态的函数(类似setState)
    function App(props) {
      let [val,setVal] = userState(0)
      
      return (
            <div className="App">
                  <div>
    				  使用数据:{val}
                      <button onClick={()={setVal(val+1)}}>点我进行数据修改</button>
                  </div>
            </div>
      );
    }
    
    // 多个状态
    // 1、声明对象类型的状态
    function App(props) {
        // 1、声明对象类型的状态
      let [val,setVal] = userState({
          vala:0,
          valb:1,
          valc:2
          })
      
      return (
            <div className="App">
                  <div>
    				  使用数据:{val.vala} -- {val.valb} -- {val.valc}
                  </div>
            </div>
      );
    }
    // 2、多次声明(推荐使用)
    function App(props) {
        let [vala,setVala] = userState(0)
        let [valb,setValb] = userState(1)
        let [valc,setValc] = userState(2)
      return (
            <div className="App">
                  <div>
    				  使用数据:{vala} -- {valb} -- {valc}
                  </div>
            </div>
      );
    }
    
    export default App;
    

    七、redux

    7.1 概念

    • javascript提供的一个可预测性的状态容器

    • 可预测性:给一个固定的输入,必定会等到一个结果

    • 集中管理react中多个组件的状态

    • 是一个专门的状态管理库

    • 需求场景。

      • 某个组件的状态需要共享的时候
      • 一个组件需要改变另外一个组件状态的时候
      • 组件中的状态需要在任何地方都可以拿到
    • 三大原则

      • 单一的数据源:整个react中的状态都会被统一管理到store
      • state是只读的。不能直接改变state,而是通过触发redux中特定方法进行修改
      • 使用纯函数来执行修改操作:action来改变redux中的state

    7.2 下载

    npm install --save redux
    

    7.3 数据读取

    # src 新建 redux 新建 reducer.js
    # 创建数据
    var obj = [
        {name:"xixi",age:18}
    ]
    
    export function data(state=obj[0].age,action){
        switch (action.type) {
            
            default:
                return state;
                break;
        }
    }
    # redux 新建 store.js
    import {createStore} from "redux"
    import {data} from "./reducer"
    export var store = createStore(data)
    # 新建 Home.js
    # App.js 引入 Home
    
    // Home.js
    import React, {Component} from 'react';
    import {store} from './store';
    class Home extends Component {
        constructor(props){
            super(props)
            this.state={
                num:store.getState()
            }
        }
        render() {
            return (
                <div>
    				home -- {this.state.num}
                </div>
            );
        }
    }
    export default Home;
    

    7.4 数据修改

    # src - redux - 新建 action.js
    // 增加
    export const add=(num)=>{
        return {type:"ADD",data:num}
    }
    // 减少
    export const del=(num)=>{
        return {type:"DEL",data:num}
    }
    # reducer.js
    var obj = [
        {name:"xixi",age:18}
    ]
    
    export function data(state=obj[0].age,action){
        switch (action.type) {
            case "ADD":
                return state+action.data
                break;
            case "DEL":
                return state-action.data
                break;
            default:
                return state;
                break;
        }
    }
    # home.js
    import React, {Component} from 'react';
    import {store} from './store';
    import * as action from './action';
    class Home extends Component {
        constructor(props){
            super(props)
            this.state={
                num:store.getState()
            }
        }
        
        componentDidMount(){
            // 监听和触发页面的修改操作
            store.subscibe(()=>{
                this.setState({
                    num:store.getState()
                })
            })
        }
        
        render() {
            return (
                <div>
    				home -- {this.state.num}
                    <button onClick={()=>{store.dispatch(action.add(1))}}>点我加1</button>
                    <button onClick={()=>{store.dispatch(action.add(2))}}>点我加2</button>
                    <button onClick={()=>{store.dispatch(action.del(1))}}>点我减1</button>
                    <button onClick={()=>{store.dispatch(action.del(2))}}>点我减2</button>
                </div>
            );
        }
    }
    export default Home;
    
  • 相关阅读:
    react-dnd例子代码学习记录
    GitKraken使用记录
    Table-dnd-tree代码分析
    umi-request请求码200,但是response是网页
    MyBatis-Plus配置输出日志
    PAT甲级1021解法
    PAT甲级1020解法
    PAT甲级1019解法
    PAT甲级1017解法
    PAT甲级1018解法
  • 原文地址:https://www.cnblogs.com/luckyzs/p/13178924.html
Copyright © 2020-2023  润新知