React—— HelloWorld

2023-05-16

React 学习笔记

    • Hello World
    • JSX (JavaScript XML) 语法规则
    • JavaScript 语法
    • 函数组件、类组件 & 属性 props
      • 组合组件
    • 生命周期函数(不全) & 状态 state
    • 事件处理
    • refs
    • 受控组件、非受控组件 & 高阶函数、函数的柯里化
    • 生命周期
    • 列表 & Key
    • NPM node 包管理器
    • React 脚手架 create-react-app
    • 网络请求库及代理
      • 网络代理
      • 1. Ajax (基于XHR XMLHttpRequest)
      • 2. Axios
      • 3. fetch (window 的新 api,为取代ajax,promise风格)
    • pubsub-js 消息发布订阅库
    • React 路由
      • 什么是路由?
      • 路由分类
      • react-router-dom
        • **路由基本使用**
        • **路由组件和一般组件**
        • **多级路径刷新页面,样式丢失问题**
        • **路由的严格匹配与模糊匹配**
        • 嵌套路由(多级路由)使用
    • JavaScript CDN 库
    • 参考

Hello World

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello, React</title>
</head>

<body>
    <div id="root"></div>
    <!-- Load React. -->
    <!-- Note: when deploying, replace "development.js" with "production.min.js". -->
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>

    <!-- Load Babel -->
    <!-- v6 <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <!-- Your custom script here -->
    <script type="text/babel">
        const element = <h1>Hello, World!</h1>;
        const container = document.getElementById('root');
        // ReactDOM.render(element, container);
        ReactDOM.createRoot(container).render(element);
    </script>
</body>

</html>

JSX (JavaScript XML) 语法规则

1. 定义虚拟D0M时,不要写引号。
2. 标签中混入JS表达式时要用}。
3. 样式的类名指定不要用class,要用className。
4. 内联样式,要用style={key:value}的形式去写。
5. 只有一个根标签
6. 标签必须闭合
7. 标签首字母
	1. 若小写字母开头,则将改标签转为htl中同名元素,若htm1中无该标签对应的同名元素,则报错。
	2. 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

JavaScript 语法

https://es6.ruanyifeng.com/#docs/destructuring

  1. console.log(2, "@");

  2. debugger;

  3. JSON
    JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串
    JSON.parse () 方法用来解析 JSON 字符串,构造由字符串描述的 JavaScript 值或对象。

     JSON.stringify({name:"zhangsan",age:18}) // '{"name":"zhangsan","age":18}'
     JSON.parse('{"name":"zhangsan","age":18}') // {name: 'zhangsan', age: 18}
    
  4. 类中方法默认开启局部严格模式,所以类中自定义方法中的 thisundefined,而不是类的实例对象!

    <script>
        class Person {
            constructor(name, age) {
                this.name = name
                this.age = age
            }
    
            say() { // 方法在类的原型对象上,供实例使用
                console.log(this)
            }
        }
    
        const p1 = new Person("zhangsan", 13)
        p1.say() // 通过实例调用,this 是 Person 实例
        const say = p1.say
        say() // 直接调用方法,this 是 undefined
    
        console.log("----------------")
    
        function fun1() {
            // 'use strict'
            console.log(this) // Window 对象-
    	}
        function fun2() {
            'use strict'
            console.log(this) // undefined
        }
        fun1()
        fun2()
    </script>
    

    在这里插入图片描述

  5. 对象属性的访问方式

    • 点属性访问器 对象.属性object.property
    • 方括号属性访问对象["属性"]object['property']
    • 对象解构 const / let { 属性同名的变量名[:别名] } = 对象const { property } = object
    const app = "appName";
    console.log(app);
    let obj = {app};
    console.log(obj); // {app: 'appName'}
    let obj2 = {app:app};
    console.log(obj2); // {app: 'appName'}
    let obj3 = {[app]: app};
    console.log(obj3); // {appName: 'appName'}
    const { appName } = obj3;
    console.log(appName); // appName
    
    // 对象解构赋值,并取别名,并赋有默认值
    const {name: b, age: nianling=5, tall=180, weight} = { name: "zhangsan" }
    console.log(b) // zhangsan
    console.log(nianling) // 5
    console.log(tall) // 180
    console.log(weight) // undefined
    

    在这里插入图片描述

函数组件、类组件 & 属性 props

React 对象三大属性1:props

<body>
    <!-- <div id="root"></div> -->
    <div id="funId"></div>
    <div id="classId"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

    <script type="text/babel">
    	// 1. 函数组件,首字母要求大写
        function FunctionWelcome(props) {
            return <h1>Hello, {props.name}</h1>;
        }

		// 2. 类组件,首字母要求大写,继承 React.Component,React 元素通过 render() 函数返回
        class ClassWelcome extends React.Component {
            render() {
                return <h1>Hello, {this.props.name}</h1>;
            }
        }

		// 3. props
		// 无论是函数组件,还是类组件,都决不能修改自身的 props。
		// React 调用组件,并将 {name: 'XXX'} 作为 props 传入。
        // ReactDOM.render(<FunctionWelcome name="老写法"/>, document.getElementById("root"));
        ReactDOM.createRoot(document.getElementById("funId")).render(<FunctionWelcome name="韩束"/>);
        ReactDOM.createRoot(document.getElementById("classId")).render(<ClassWelcome name="克拉斯"/>);
    </script>
</body>

组合组件

<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        function Welcome(props) {
            return <h1>Hello, {props.name}</h1>;
        }

        function App() {
            return (
                <div>
                    <Welcome name="Sara" />
                    <Welcome name="Cahal" />
                    <Welcome name="Edite" />
                </div>
            );
        }

        ReactDOM.render(<App />, document.getElementById('root'));
    </script>
</body>

生命周期函数(不全) & 状态 state

React 对象三大属性2:state

<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        class Clock extends React.Component {
            constructor(props) {
                // Class 组件应该始终使用 props 参数来调用父类的构造函数
                super(props);
                // 初始化状态数据
                this.state = { date: new Date() };
            }

            // 生命周期函数1:组件已被渲染到 DOM 中后调用
            componentDidMount() {
                this.timerID = setInterval(
                    () => this.tick(),
                    1000
                );
            }

            // 生命周期函数2:组件将卸载时调用
            componentWillUnmount() {
                clearInterval(this.timerID);
            }

            tick() {
                // 更新状态数据,必须用 this.setState() 函数。
                // 直接修改状态数据无效,如 this.state.date = new Date(); 无效
                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'));
    </script>
</body>
  • 组件生命周期函数

    • componentDidMount 组件已被渲染到 DOM 中后调用
    • componentWillUnmount 组件将卸载时调用
  • state 使用注意事项

    • 只能在构造函数或类属性上初始化 state

    • 只能使用 this.setState(函数或对象) 更新状态数据,直接更新 state 状态数据无效!

    • state 的更新可能是异步的。出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。

      // Wrong
      this.setState({
              counter: this.state.counter + this.props.increment,
          });
      }
      
      // Correct
      this.setState((state, props) => ({
          counter: state.counter + props.increment
      }));
      
      // Correct
      this.setState(function (state, props) {
          return {
              counter: state.counter + props.increment
          };
      });
      
    • state 的更新会被合并
      当你调用 setState(对象) 的时候,React 会把你提供的对象合并到当前的 state。

    • 除了拥有并设置 state 的组件之外,其他组件都无法访问该 state。不过,组件可以选择把它的 state 作为 props 向下传递到它的子组件中。

事件处理

https://zh-hans.reactjs.org/docs/handling-events.html

React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  1. React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  2. 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。如 onChange={this.saveUsername},其含义为:大括号中同 js语法,将大括号中结果(此处结果为一个函数)赋值给onChange,React 负责调用onChange。
  3. 在 React 中不能通过返回 false 的方式阻止默认行为,必须显式的使用 preventDefault 。
<body>
    <a href="#" onclick="console.log(123);">原生js事件,注意浏览器地址栏URL变化</a><br />
    <a href="#" onclick="console.log(123);return false;">原生js通过返回false阻止默认事件</a><br />
    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        function Fun() {
            function handleClick(event) {
                event.preventDefault();
                console.log(event);
            }

            return (
                <div>
                    <a href="https://www.baidu.com" onClick={(e) => { handleClick }}>React 通过显示调用阻止默认事件函数阻止事件</a><br />
                    <a href="https://www.baidu.com" onClick={(e) => { event.preventDefault(); console.log(e.target, e) }}>React 通过显示调用阻止默认事件函数阻止事件, e.target是发生事件的DOM元素</a>
                </div>
            );
        }
        ReactDOM.createRoot(document.getElementById("root")).render(<Fun />)
    </script>
</body>

refs

React 对象三大属性3:DOM 节点引用 refs

<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        class App extends React.Component {
            input4Ref = React.createRef()

            input3 = (c) => {
                console.log("函数形式", c);
            }

            render() {
                return (
                    <div>
                        <input ref="input1" defaultValue="用法1(过时).这是字符串形式ref,效率低" type="text" style={{ width: "50%", color: "#f00" }} name="username" id="uid" /><br />
                        <input ref={(c) => { this.input2 = c; console.log(c); }} defaultValue="用法2.内联函数形式ref,react会自动调用ref函数,更新过程中会被执行两次,第一次传null,第二次传dom对象" type="text" /><br />
                        <input ref={this.input3} defaultValue="用法3.回调函数形式的ref,react会自动调用ref函数,更新过程中会被执行两次,第一次传null,第二次传dom对象" type="text" name="username" id="uid" /><br />
                        <input ref={this.input4Ref} defaultValue="用法4.类绑定的回调,指定回调函数由react创建ref" type="text" name="username" id="uid" /><br />

                        <input ref={(c) => { this.btn = c }} onClick={(e) => { console.log("不要滥用ref,譬如此按钮的ref可以省略", e.target === this.btn); console.log(1, this.refs.input1); console.log(2, this.input2); console.log(3, this.input3); console.log(4, this.input4Ref.current); this.input4Ref.current.value = "React.createRef"; }} type="button" value="click" />
                    </div>
                );
            }
        }

        ReactDOM.createRoot(document.getElementById("root")).render(<App />)
    </script>
</body>

受控组件、非受控组件 & 高阶函数、函数的柯里化

<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        class FormApp extends React.Component {
            handleSubmit = (event) => {
                event.preventDefault();
                const { username, password } = this;
                // alert("用户名:" + username.value + ", 密码:" + password.value)
                alert(`用户名:${username.value},密码:${password.value}`);
            }

            state = {
                username: "",
                password: ""
            }

            saveUsername = (e) => {
                this.setState({ username: e.target.value });
            }

            savePassword = (e) => {
                this.setState({ password: e.target.value });
            }

            handleSubmit2 = (event) => {
                event.preventDefault();
                alert(`用户名:${this.state.username},密码:${this.state.password}`);
            }

            // 高阶函数:参数或返回值也为函数的函数。
            // 函数的柯里化:通过函数调用继续返回函数的方式,多次接收参数最后统一处理的函数编码形式。
            // 如定义:
            // f = (a) => {
            //     return (b) => {
            //         return (c) => {
            //             return a + b + c;
            //         }
            //     }
            // }
            // console.log(f(1)(2)(3)) // 6
            saveData = (dataType) => {
                return (event) => {
                    this.setState({ [dataType]: event.target.value });
                }
            }

            saveData2 = (event, dataType) => {
                return (event) => {
                    this.setState({ [dataType]: event.target.value });
                }
            }

            render() {
                return (
                    <div>
                        <h1>1. 非受控组件,大量使用ref,性能相对低(不太推荐)</h1>
                        <form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit}>
                            用户名:<input ref={c => this.username = c} type="text" name="username" /><br />
                            密码:<input ref={c => this.password = c} type="password" name="password" /><br />
                            {/* <input type="submit" value="登陆"/>*/}
                            <button>登陆</button>
                        </form><br />

                        <h1>2. 受控组件(推荐)</h1>
                        <form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit2}>
                            用户名:<input onChange={this.saveUsername} type="text" name="username" /><br />
                            密码:<input onChange={this.savePassword} type="password" name="password" /><br />
                            <button>登陆</button>
                        </form>


                        <h1>3. 高阶函数(更推荐)</h1>
                        <form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit2}>
                            用户名:<input onChange={this.saveData("username")} type="text" name="username" /><br />
                            密码:<input onChange={this.saveData("password")} type="password" name="password" /><br />
                            <button>登陆</button>
                        </form>

                        <h1>4. 不使用高阶函数同样实现效果(最推荐)</h1>
                        <form method="post" action="http://www.baidu.com" onSubmit={this.handleSubmit2}>
                            用户名:<input onChange={(event)=>{this.setState({"username": event.target.value})}} type="text" name="username" /><br />
                            密码:<input onChange={(event)=>{this.setState({"password": event.target.value})}} type="password" name="password" /><br />
                            <button>登陆</button>
                        </form>
                    </div>
                );
            }
        }
        ReactDOM.createRoot(document.getElementById("root")).render(<FormApp />);
    </script>
</body>

生命周期

https://zh-hans.reactjs.org/docs/react-component.html#the-component-lifecycle
生命周期图

在这里插入图片描述
在这里插入图片描述

注: 图中的 shouldCompnentUpdate 方法返回值为 false 时,即走图中 × 不再渲染 。加粗样式

在这里插入图片描述

列表 & Key

列表的 key 确保唯一不变性
确保key不适用索引,因为含有input元素时倒序增加、增删操作都会产生bug,不仅仅是性能低问题。
如果你提取出一个 ListItem 组件,你应该把 key 保留在数组中的这个 元素上,而不是放在 ListItem 组件中的 <li> 元素上。
key 值在兄弟节点之间必须唯一

<body>
    <div id="root"></div>
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="text/babel">
        function ListItem(props) {
            // 正确!这里不需要指定 key:
            return <li>{props.value}</li>;
        }

        function NumberList(props) {
            const numbers = props.numbers;
            const listItems = numbers.map((number) =>
                // 正确!key 应该在数组的上下文中被指定
                <ListItem key={number.toString()} value={number} />
            );
            return (
                <ul>
                    {listItems}
                </ul>
            );
        }

        const numbers = [2, 3, 5, 33, 22, 11];
        ReactDOM.createRoot(document.getElementById("root")).render(<NumberList numbers={numbers} />);
    </script>
</body>

NPM node 包管理器

npm(“Node 包管理器”)是 JavaScript 运行时 Node.js 的默认程序包管理器。
npm 由两个主要部分组成:
	用于发布和下载程序包的 CLI(命令行界面)工具
	托管 JavaScript 程序包的  在线存储库

菜鸟教程 nodejs

React 脚手架 create-react-app

  1. 全局安装

    npm i[nstall] -g create-react-app

    可另外再安装 yarn:npm i -g yarn

  2. 切换到想创建工程的目录,创建项目

    create-react-app hello-react

  3. 进入工程目录

    cd hello-react

  4. 启动工程

    npm startyarn start

网络请求库及代理

网络代理

因 Ajax 同源策略影响,需配置代理,通过代理间接获取非同源资源。

配置代理方式:

  1. package.json

    "proxy": "http://localhost:8080"
    

    则所有向原本3000端口的请求,3000端口没有的资源都会转发到8080端口访问。

  2. 通过 http-proxy-middleware 模块代理实现

    新建 src/setupProxy.js 文件,内容如下:

    // setupProxy.js
    // react 17
    const { proxy } = require("http-proxy-middleware");
    module.exports = function (app) {
      // 将原有 http://localhost:3000/api1/students 通过如下配置,代理将访问 http://localhost:8080/students
      app.use(
        proxy("/api1", {
          target: "http://localhost:8080",
          changeOrigin: true,
          pathRewrite: { "^/api1": "" },
        }),
        proxy("/api2", {
          target: "http://localhost:8081",
          changeOrigin: true,
          pathRewrite: { "^/api2": "" },
        })
        // ...
      );
    };
    
    // react 18
    const { createProxyMiddleware } = require("http-proxy-middleware");
    module.exports = function (app) {
      app.use(
        createProxyMiddleware("/api1", {
          target: "http://localhost:8080",
          changeOrigin: true,
          pathRewrite: { "^/api1": "" },
        }),
        createProxyMiddleware("/api2", {
          target: "http://localhost:8081",
          changeOrigin: true,
          pathRewrite: { "^/api2": "" },
        }),
        createProxyMiddleware("/apiGithub", {
          target: "https://api.github.com",
          changeOrigin: true,
          pathRewrite: { "^/apiGithub": "" },
        })
      );
    };
    

1. Ajax (基于XHR XMLHttpRequest)

https://react.docschina.org/docs/faq-ajax.html

2. Axios

Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js

npm install axios

import React, { Component } from "react";
import axios from "axios";

class Header extends Component {
  search = () => {
    const keyword = this.keywordElement.value;
    console.log(keyword);

    this.props.updateState({ isFirst: false, isLoading: true, errorMsg: "" });

    axios
      // .get("http://localhost:3000/api1/javaweb_demo2_war_exploded/")
      .get(`http://localhost:3000/apiGithub/search/users?q=${keyword}`)
      .then((response) => {
        // 处理成功情况
        console.log(response.data);
        this.props.updateState({ users: response.data.items });
      })
      .catch((error) => {
        // 处理错误情况
        console.log(error);
        this.props.updateState({ errorMsg: error.message });
      })
      .then(() => {
        // 总是会执行
        this.props.updateState({ isLoading: false });
      });
  };

  render() {
    return (
      <div>
        <div>Search Github Users</div>
        <br />
        <input
          ref={(c) => (this.keywordElement = c)}
          type="text"
          name="keyword"
          id="keyword"
        />
        <button onClick={this.search}>搜索</button>
      </div>
    );
  }
}

export default Header

3. fetch (window 的新 api,为取代ajax,promise风格)

fetch 详解见 MDN
或网友前端阿彬的博文 fetch与XHR(ajax,axios)的区别与优势

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));

pubsub-js 消息发布订阅库

github地址
npmjs地址

类似 android 中 EventBus,基本使用:

// 1. 引入库
import PubSub from 'pubsub-js'
// or when using CommonJS
const PubSub = require('pubsub-js');

// 2. 订阅
var mySubscriber = (msg, data)=> {
    console.log( msg, data );
};
var token = PubSub.subscribe('MY TOPIC', mySubscriber);

// 3. 发布
// publish a topic asynchronously
PubSub.publish('MY TOPIC', 'hello world!');
// publish a topic synchronously, which is faster in some environments,
// but will get confusing when one topic triggers new topics in the
// same execution chain
// USE WITH CAUTION, HERE BE DRAGONS!!!
PubSub.publishSync('MY TOPIC', 'hello world!');

// 4. 取消发布
// unsubscribe this subscriber from this topic
PubSub.unsubscribe(token);
// unsubscribe mySubscriber from ALL topics
PubSub.unsubscribe(mySubscriber);

React 路由

什么是路由?

路由就是一个路径作为key,function或component作为value的映射关系。

路由分类

  • 前端路由
    1. 浏览器路由,value是component,用于展示页面内容。
    2. 注册路由:
    3. 工作过程:当浏览器的path变为/test时,当前路由组件就变成Test组件。
  • 后端路由
    1. value是function,用来处理客户端请求。
    2. 注册路由:router.get(path, function(req,res))
    3. 工作过程:当node接收到请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。

react-router-dom

reactrouter 官网 最新版本 V6.4
react-router 中文文档(印记中文)

路由基本使用

  • 明确好界面导航区和展示区。
  • 导航区的a标签改为Link标签 <Link to='/xxx'>Demo</Link>
  • 展示区写Route标签进行路径的匹配 <Route path='/xxxx' component={Demo}/>
  • <App/>的最外层包裹一个<BrowerRouter><HashRouter>
  • Switch 最多只匹配一个路由路径,展示对应路径的的组件。
  • Redirect 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。
import {BrowserRouter} from 'react-router-dom'`locathost:3000/home`import {HashRouter} from 'react-router-dom' 路径后面有个#,如`locathost:3000/#/home`,警号后面的不会发送给后台,为前台资源

import {Link, NavLink, Route} from 'react-router-dom'

{/* 编写路由链接, 标签体内容是一个特殊的属性:children属性 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home" children="Home"/>

{/* 注册路由。
	如果是/about路径,就在此渲染About组件。
	Switch组件作用:只展示第一个匹配路径的组件,如下不会显示Test组件内容。
	Redirect:重定向。如果前面的路径都不匹配,则使用Redirect配置的路径相对的组件。如下,对应的为About组件。
 */}
<Switch>
	<Route path="/about" componen={About}/>
	<Route path="/home" component={Home}/>
	<Route path="/home" component={Test}/> 
	<Redirect to="/about"/>
</Switch>
  • 如果使用了 Bootstrap,切换链接按钮样式可使用路由标签 ,其 activiteClassName属性值指定class样式,默认class为 active,正好和Bootstrap一致 ,也可自定义样式如 myClass
    <NavLink activeClassName="myClass" className="list-group-item" to="/about">About</Link>
    
    <style>
    /* !important 提高样式权重,将覆盖任何其他样式声明,破坏样式表中级联规则,不建议使用 */
    .myClass {
      background-color: #ff0 !important; 
      color: white !important;
    }
    </style>
    

路由组件和一般组件

  1. 写法不同
    • 一般组件:
    • 路由组建:
  2. 存放位置不同
    • 一般组件:components
    • 路由组件:pages
  3. 接收到的props不同
    • 一般组件:写组件标签时传递了什么就能收到什么
    • 路由组件:接收到 3 个固定的属性
      history:
      	go: f go(n)
      	goBack: f goBack()
      	goForward: f goForward()
      	push: f push(path, state)
      	replace: f replace(path, state)
      location:
      	pathname:"/about"
      	search:""
      	state:undefined
      match:
      	params:{}
      	path:"/about"
      	url:"/about"
      

多级路径刷新页面,样式丢失问题

  • 原因:资源引入使用了相对路径,并使用路由的 BrowerRouter 标签。刷新后,多级 url 路径错误。
  • 解决方案:
    • 不使用相对路径,要使用绝对路径(相对 public 文件夹),如/test/a.css (常用)
    • 使用%PUBLIC_URL%作为前缀,如%PUBLIC_URL%/test/a.css (常用)
    • 更换BrowerRouterHashRouter

路由的严格匹配与模糊匹配

  • 默认使用的是模糊匹配(即输入的路径必须包含要匹配路径,且前面的顺序要一致)
  • 开启严格匹配写法:<Route exact={true} path="/about" component={About}/>
  • **严格匹配不要随便开启,需要再开。**有些时候开启会导致无法继续匹配二级路由问题。

嵌套路由(多级路由)使用

JavaScript CDN 库

  1. staticfile
  2. bootcdn
  3. cdnjs
  4. jsdelivr
  5. 75CDN
  6. 字节跳动静态资源公共库
  7. cdnjs.loli.net

参考

  • MDN
  • React 官方中文教程
  • ES6 入门教程
  • 印记中文(深入挖掘国外前端新领域,为国内 Web 前端开发人员提供优质文档)
  • Babel 官网
  • 尚硅谷 React 视频教程
  • 什么是 npm —— 写给初学者的编程教程
  • 浏览器的同源策略机制以及跨域请求
  • 跨域不求人,自己动手解决react跨域问题
  • Bootstrap
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React—— HelloWorld 的相关文章

  • React中的“计算属性”

    React中的 计算属性 相信许多学习过vue的小伙伴对计算属性都不陌生吧 计算属性能帮我们数据进行一些计算操作 计算属性是依赖于data里面的数据的 在vue中只要计算属性依赖的data值发生改变 则计算属性就会调用 那React中也有计
  • React仿写网易云音乐项目

    文章目录 一 项目功能说明 二 最终效果 三 文件目录结构说明 四 项目技术栈 五 核心技术 1 配置项目别名 craco craco 2 使用reset css进行 css 重置 3 使用CSS Sprites 精灵图 4 使用 memo
  • React重新渲染的触发机制及其优化策略

    React是一个用于构建用户界面的JavaScript库 它的核心特点之一是使用虚拟DOM Virtual DOM 来实现高效的组件渲染 那组件重新渲染的机制是如何呢 基于这些机制 如果进行优化呢 虚拟DOM是一个用JavaScript对象
  • React 组件通讯

    目录 1 组件通讯 概念 1 组件的特点 2 知道组件通讯意义 总结 2 组件通讯 props 基本使用 1 传递数据和接收数据的过程 2 函数组件使用 props 3 类组件使用 props 总结 3 组件通讯 props 注意事项 1
  • state和props的区别__react

    首先说明 state和props是每个组件都有的 其次 state可变 但props不可变 这是官网给出的说法 但实操过程中 state的确可变 但props也可以变 是不是fb搞错了 当然不是 这里的可变与不可变 说的是改变后 是否会重新
  • React的State Hook用法详解

    一 State Hook是啥 State Hook 就是指 useState 这个特殊函数 让你不用编写class 就可以使用state特性 换言之就是让 函数组件 拥有 state 特性 对数据进行动态更新 二 class中的state
  • ant design pro v5 配置拦截器,header

    ant design pro v5 配置拦截器 header 1 资料文档 https umijs org zh CN plugins plugin request requestinterceptors 2 编写app tsx 我这里是自
  • 对 React Hook的闭包陷阱的理解,有哪些解决方案?

    hooks中 奇怪 其实符合逻辑 的 闭包陷阱 的场景 同时 在许多 react hooks 的文章里 也能看到 useRef 的身影 那么为什么使用 useRef 又能摆脱 这个 闭包陷阱 搞清楚这些问题 将能较大的提升对 react h
  • react基础--组件通讯:props基础、子传父、父传子、兄弟组件通讯、context跨级组件、props进阶

    目录 一 props基础 1 1 概述 1 2 函数组件通讯 1 2 1 基本用法 1 2 1 对象数据传递 1 3 类组件通讯 1 4 props的特点 二 组件通讯三种方式 2 1 父传子 2 2 子传父 2 3 兄弟组件通讯 三 co
  • chrome浏览器安装redux-devtools调试工具

    chrome浏览器安装redux devtools调试工具 1 点击进入https www chromefor com 2 在搜索框搜索redux 3 找到最新版本 Redux DevTools v2 17 0 进行下载 4 选择下载线路
  • React页面设计初体验

    1 定制路由 export default login path login name login component layouts BlankLayout routes path login component Login Index
  • 关于Vue.js和React.js,听听国外的开发者怎么说?

    VueJS 与 ReactJS 到底怎么样如何 听听别人怎么说 使用所有新的库和框架 很难跟上所有这些库和框架 也就是说 这就需要您决定哪些是值得花时间的 让我们看看人们说什么 和Vue JS一起工作是很愉快的 我发现学习曲线很浅 然而 这
  • React-(4)React中的事件绑定

    React中的事件绑定 在 React 组件中 每个方法的上下文都会指向该组件的实例 即自动绑定 this 为当前组件 而且 React 还会对这种引用进行缓存 以达到 CPU 和内存的最优化 在使用 ES6 classes 或者纯函数时
  • Ant Design Pro从零到一(认识AntD)

    废话 在我们第一次接触AntD的时候 会遇到两个东西 一个是Ant Design 另一个是Ant Design Pro 他们的官网分别是 Ant Design 一套企业级 UI 设计语言和 React 组件库 Ant Design Pro
  • Umi+Dva初印象<基础应用,结构,流转逻辑>

    目录 前言 知识储备 generator函数 Dva初识 实际交互 函数式组件 class组件 前言 项目初始为umi脚手架进行初始化 lt 初始化过程 http t csdn cn cuTaY gt 工程中加载了umi自带的antd ui
  • React官方文档--Lifting State Up

    Lifting State Up 如果 几个组件需要同时影响并且修改同一个数据 我们建议将这个共享状态进行提升 给他们最近的共同祖先 在这个部分 我们将要创建一个温度计算器来判断水会不会在给定温度下沸腾 我们将从一个叫做BoilingVer
  • React实现关键字高亮

    先看效果 实现很简单通过以下这个函数 highLight text keyword gt return text split keyword flatMap str gt span keyword span str slice 1 展示某段
  • 如何替换对象的key值

    发生的场景 现在用antd组件库 有些组件想渲染数据的话 我要根据他们官网给的字段名称对应起来才能渲染上去 这个是复选框选中 保存的时候 字段需要按照后台约定的传入code value 1 常规循环遍历 大招来了 哈哈哈 才疏学浅 我觉得是
  • 黑马React:基础拓展

    黑马React D10 基础拓展 Date December 18 2023 useReducer 基础使用 作用 让 React 管理多个 相对关联 的状态数据 补充 和useState的作用类似 用来管理相对复杂的状态数据 特点 use
  • React Jsx转换成真实DOM过程?

    面试官 说说React Jsx转换成真实DOM过程 一 是什么 react 通过将组件编写的 JSX 映射到屏幕 以及组件中的状态发生了变化之后 React 会将这些 变化 更新到屏幕上 在前面文章了解中 JSX 通过 babel 最终转化

随机推荐

  • 机器视觉中坐标系转换

    机器视觉 立体视觉等等方向常常涉及到四个坐标系 xff1a 世界坐标系 相机坐标系 图像坐标系 像素坐标系 整体预览如下 1 世界坐标系和相机坐标系 世界坐标系 xff0c 也称为测量坐标系 xff0c 它是一个三维直角坐标系 Xw Yw
  • 机械臂DH参数总结

    DH参数 DH参数 xff08 Denavit Hartenberg parameters xff09 是一个用四个参数表达两对关节连杆之间位置角度关系的机械臂数学模型和坐标系确定系统 DH选的四个参数都的含义如下 xff1a link l
  • 机器人正解和逆解

    正解FK 给定机器人各关节的角度 xff0c 计算出机器人末端的空间位置 逆解IK 已知机器人末端的位置和姿态 xff0c 计算机器人各关节的角度值 挖个坑待完善
  • LeetCode—232 用栈实现队列 Cpp&Python

    LeetCode 225 用队列实现栈 Cpp amp Python 一 方法与思路二 C 43 43 代码三 Python代码 一 方法与思路 使用栈实现队列的下列操作 xff1a push x 将一个元素放入队列的尾部 pop 从队列首
  • E: Unable to locate package解决办法

    问题 xff1a E Unable to locate package 解决 xff1a sudo apt span class token operator span get updade
  • Yolo框架简介

    YOLO xff08 You Only Look Once xff09 是一种基于深度神经网络的对象识别和定位算法 xff0c 其最大的特点是运行速度很快 xff0c 可以用于实时系统 现在YOLO已经发展到v4版本 论文地址 xff1a
  • Ubuntu下编辑权限只读文件的方法

    首先要注意的是只读文件一般都是系统文件 xff0c 或者软件配置文件 xff0c 修改时要尤其谨慎 本文提供两种方法 xff1a 方法一 首先安装一个插件 span class token function sudo span apt sp
  • Ros下Aruco模块的使用

    生成ARUCO ROS MARKER 链接 http chev me arucogen 首先启动ros roscore 打开相机节点 xff0c 在此提供usb相机与Realsense D435i的启动方法 xff1a roslaunch
  • 脚气、灰指甲治疗实验方案

    脚气 xff08 已临床实验 xff09 脚气 xff0c 又叫足廯 香港脚 糜烂性脚气 症状 xff1a 80 都是这种类型 常见于多汗人群 角质层被汗水浸软 xff0c 发白了以后 xff0c 走动不断摩擦表皮脱落 xff0c 露出鲜红
  • VS2015显示“正在从以下位置加载符号“的解决办法

    解决方法 xff1a VS 工具 选项 调试 符号 看到 MicroSoft符号服务器 xff0c 去掉方框中的 xff0c 确定即可 xff0c 之后就不会再调试时加载
  • 【面包】STM32学习笔记(二) --- USART 串口通信学习总结

    tip xff1a 如有错误 xff0c 希望指出 xff0c 非常感谢 xff01 目录 简介一 USART是什么 xff1f 二 问答通信方式1 USART和UART区别2 单工 半双工 全双工区别 三 代码实验1 说明2 代码初始化配
  • [论文阅读笔记] Reciprocal n-body Collision Avoidance(ORCA/RVO2)

    论文阅读 Reciprocal n body Collision Avoidance ORCA RVO2 文章目录 论文阅读 Reciprocal n body Collision Avoidance ORCA RVO2 论文地址Intro
  • 在VSCode中搭建C++编译环境

    在VSCode中搭建C 43 43 编译环境 VSCode当中搭建C 43 43 环境下载VSCode下载MinGW配置文件撰写测试小程序 VSCode当中搭建C 43 43 环境 vscode作为一款轻量级编程软件深受编程人员喜爱 xff
  • 【C++学习笔记】头文件详解

    个人整理学习用 xff0c 非教材 xff0c 有错误欢迎指正 头文件 究竟什么是头文件 xff1f 首先说明一个概念 xff0c 所谓的文件后缀并不是必须的 xff0c 在Linux下这种特点尤为明显 对于编译器来说 xff0c 无论是
  • 编程实现字符串连接函数strcat()

    按如下函数原型编程实现字符串连接函数strcat 的功能 void MyStrcat char dstStr char srcStr 输入提示信息 xff1a Input a string Input another string 输入字符
  • UDP通讯

    目录 利用DatagramSocket发送和接收UDP数据报 DatagramPacket构造方法说明 利用DatagramPacket和Datagramsocket简单实现服务器和客户端的通信 UDP协议通讯的用户状态跟踪 利用Datag
  • ubuntu 下C/C++文件编写

    1 Ubuntu下c cpp文件 1 1 cmake方式编译 cmake通常建立CmakeLists txt xff0c 通过cmake命令生成makefile文件编译工程 文件内容 xff1a span class token numbe
  • C语言基础入门:链表详解篇

    链表概述 链表是一种常见的重要的数据结构 它是动态地进行存储分配的一种结构 它可以根据需要开辟内存单元 链表有一个 头指针 变量 xff0c 以head表示 xff0c 它存放一个地址 该地址指向一个元素 链表中每一个元素称为 结点 xff
  • Linux c udp广播

    文章目录 1 对比2 代码2 1 服务端2 2 客户端 1 对比 服务端 xff1a 需要利用这个函数开发套接字的发广播权限 xff0c 并且需要客户端地址绑定为广播地址 span class token function setsocke
  • React—— HelloWorld

    React 学习笔记 Hello WorldJSX JavaScript XML 语法规则JavaScript 语法函数组件 类组件 amp 属性 props组合组件 生命周期函数 xff08 不全 xff09 amp 状态 state事件