创建react项目
react的vscode插件
Simple React Snippets
也可以使用自定义的
如何修改配置文件
1.npm run eject 暴露所有的配置文件 不可逆的,在发射前需要提交git文件
2.安装react-app-rewired 这个包需要报pakage.json中的脚本配置修改为下面代码,再在更目录下创建config-overrides.js的配置
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
}
React.StrictMode是什么?
StrictMode 检查项目中潜在问题。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
Fragment 类似于 vue中的template
react项目文件中 为什么都要导入react包
import React from "react";
import ReactDOM from 'react-dom'
let h1 = <h1>123</h1> //babel会编译这个 下面有编译的地址
function App() {
return h1
}
ReactDOM.render(<App />, document.getElementById('root'))
export default App;
let h1 = /*#__PURE__*/React.createElement("h1", null, "123");
可以看到这里用到了React 所以需要导入
用到了jsx语法 所以每个文件都需要导入react包
类组件 和 函数组件
函数组件使用hooks 可以替换类组件
受控组件和 非受控组件
<input value={name} onChange={this.changeName} /> // change = e => this.setState({name:e.target.value})}
<input ref={(el)=>{this.qq = el }} /> // this.qq 就是当前dom
react常用写法
<button onClick={this.fn.bind(this)}>btn</button> //当fn中用到 this时 需要用bind绑定this
<div dangerouslySetInnerHTML={{ __html:'<h2>h2</h2>' }} /> // 渲染字符串dom
{arr.map(item => { })} //渲染数组
{bol ? a : b} // 三元运算符 类似v-if
<div id={id} className={className} style={{ height: '30px' }}>{text}</div>//花括号 可以写js语句
fn = () => {this.props.change([])} // 子组件触发 父组件传过来的方法change 间接修改父组件数据
setState注意事项
react生命周期钩子
组件复合
redux
react-redux
react-router
1. react-router
2. react-router中??档
react-router包含3个库,react-router、react-router-dom和react-router-native。
react-router提供最基本的路由功能,实际使的时候我们不会直接安装react-router,
是根据应运的环境选择安装react-router-dom(在浏览器中使)
或react-router-native(在rn中使)。
react-router-dom和react-router-native都依赖react-router,
所以在安装时,react-router也会动安装,创建web应,使:
npm install --save react-router-dom
import React, { Component } from 'react';
import { BrowserRouter as Router, Link, Route, useParams, Switch, withRouter } from 'react-router-dom';
export default class RouterPage extends Component {
render() {
return (
<div>
<h3>RouterPage</h3>
<Router>
{/* 添加Switch表示仅匹配?个 解决下面的EmptyPage*/}
<Switch>
<Link to="/">??</Link>
<Link to="/user">?户中?</Link>
{/* 根路由要添加exact,实现精确匹配 解决/ 和 /user同时显示 */}
<Route
exact
path="/"
component={HomePage}
//children={() => <div>children</div>} 优先级高
//render={() => <div>render</div>}
// children 优先级高 跟其他的Route不是互斥的
// component 优先级中 跟其他的Route互斥的
// render 优先级低 跟其他的Route互斥的
/>
<Route path="/user" component={UserPage} />
<Route component={EmptyPage} />
</Switch>
</Router>
</div>
);
}
}
路由重定向
import { Redirect, Route } from 'react-router'
<Redirect to={{ pathname: '/login', state: { redirect: path } }} />;
const { redirect = '/' } = location.state || {}
动态路由
<Route path="/search/:id" children={<SearchComponent />} />
function SearchComponent(props) {
const { id } = useParams(); // props.match.params;
return (
<div>
<Link to={"/search/" + id + "/detail"}>详情</Link>
<Route
path={"/search/" + id + "/detail"}
children={<DetailComponent />}
/>
</div>
);
}
{/* 渲染component的时候会调用React.createElement,如果使用下面这种匿名函数的形式,每次都会生成一个新的匿名的函数,
导致生成的组件的type总是不相同,这个时候会产生重复的卸载和挂载 */}
{/* 错误举例 课下自己尝试下 观察下child的didMount和willUnmount函数 */}
<Route component={() => <Child count={count} />} /> //state变化会 反复执行 挂载和卸载
<Route component={() => <FunctionChild count={count} />} />//state变化会 反复执行 挂载和卸载
{/* 下面才是正确的示范 */}
<Route render={() => <Child count={count} />} />
<Route render={() => <FunctionChild count={count} />} />
{/* children 呢 */}
<Route children={() => <Child count={count} />} />
<Route children={() => <FunctionChild count={count} />} />
部署不是根文件 服务于子文件夹 就用到了 basename
纯组件
React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实
现 shouldComponentUpdate() , React.PureComponent 中以浅层对 prop 和 state 的式来
实现了该函数。
如果赋予 React 组件相同的 props 和 state, render() 函数会渲染相同的内容,那么在某些情况下使
React.PureComponent 可提性能。
React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层较。如果对象中
包含复杂的数据结构,则有可能因为法检查深层的差别,产错误的对结果。仅在你的
props 和 state 较为简单时,才使 React.PureComponent ,或者在深层数据结构发变化时
调 forceUpdate() 来确保组件被正确地更新。你也可以考虑使 immutable 对象加速嵌套
数据的较。
此外, React.PureComponent 中的 shouldComponentUpdate() 将跳过所有组件树的 prop
更新。因此,请确保所有组件也都是“纯”的组件。
import React, { Component, PureComponent } from "react";
export default class PureComponentPage extends PureComponent {
constructor(props) {
super(props);
this.state = {
counter: 0,
// obj: {
// num: 2,
// },
};
}
setCounter = () => {
this.setState({
counter: 100,
// obj: {
// num: 200,
// },
});
};
render() {
const { counter, obj } = this.state;
console.log("render");
return (
<div>
<h1>PuerComponentPage</h1>
<div onClick={this.setCounter}>counter: {counter}</div>
</div>
);
}
}
Hook
自定义hook 和 hook规则
<p>{useClock().toLocaleTimeString()}</p>
//?定义hook,命名必须以use开头
function useClock() {
const [date, setDate] = useState(new Date());
useEffect(() => {
console.log("date effect");
//只需要在didMount时候执?就可以了
const timer = setInterval(() => {
setDate(new Date());
}, 1000);
return () => clearInterval(timer);//清除定时器,类似willUnmount
}, []);
return date;
}
Hook 就是 JavaScript 函数,但是使?它们会有两个额外的规则:
只能在函数最外层调? Hook。不要在循环、条件判断或者?函数中调?。
只能在 React 的函数组件中调? Hook。不要在其他 JavaScript 函数中调?。(还有?个地?可
以调? Hook —— 就是?定义的 Hook 中。)
hook api 之usememo 和 usecallback
useMemo
把“创建”函数和依赖项数组作为参数传 useMemo ,它仅会在某个依赖项改变时才重新计算
memoized 值。这种优化有助于避免在每次渲染时都进开销的计算。
import React, { useState, useMemo } from "react";
export default function UseMemoPage(props) {
const [count, setCount] = useState(0);
const expensive = useMemo(() => {
console.log("compute");
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}, [count]);//只有count变化,这?才重新执?
const [value, setValue] = useState("");
return (
<div>
<h3>UseMemoPage</h3>
<p>expensive:{expensive}</p>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>add</button>
<input value={value} onChange={event => setValue(event.target.value)} />
</div>
);
}
useCallback
把内联回调函数及依赖项数组作为参数传 useCallback ,它将返回该回调函数的 memoized 版本,
该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使引相等性去避
免必要渲染(例如 shouldComponentUpdate )的组件时,它将常有。
import React, { useState, useCallback, PureComponent } from "react";
export default function UseCallbackPage(props) {
const [count, setCount] = useState(0);
const addClick = useCallback(() => {
let sum = 0;
for (let i = 0; i < count; i++) {
sum += i;
}
return sum;
}, [count]);
const [value, setValue] = useState("");
return (
<div>
<h3>UseCallbackPage</h3>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>add</button>
<input value={value} onChange={event => setValue(event.target.value)} />
<Child addClick={addClick} />
</div>
);
}
class Child extends PureComponent {
render() {
console.log("child render");
const { addClick } = this.props;
return (
<div>
<h3>Child</h3>
<button onClick={() => console.log(addClick())}>add</button>
</div>
);
}
}
useCallback(fn, deps) 相当于 useMemo(() => fn, deps) 。