render prop
class Cat extends React.Component {
render() {
const mouse = this.props.mouse;
return (
<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
);
}
}
class Mouse extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 0, y: 0 };
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{/*
使用 `render`prop 动态决定要渲染的内容,
而不是给出一个 <Mouse> 渲染结果的静态表示
*/}
{this.props.render(this.state)}
</div>
);
}
}
class MouseTracker extends React.Component {
render() {
return (
<div>
<h1>移动鼠标!</h1>
<Mouse render={mouse => (
<Cat mouse={mouse} />
)}/>
</div>
);
}
}
`
HOC的使用
export default function Index() {
return (
<div>
<HOC></HOC>
<HOC1
render={(render: any) => (
<div>
<div>{render.type}</div>
</div>
)}
></HOC1>
</div>
);
}
HOC的定义
export function HOC(WrappedComponent) {
const newProps = { type: "HOC" };
return (props) => <WrappedComponent {...props} {...newProps} />;
}
--------------------------------------
import React from "react";
import HOC, { HOC1 } from "src/hooks/Hoc.jsx";
function testHoc() {
return <div>useHoc</div>;
}
export default HOC(testHoc);
--------------------------------------------
export function HOC1(prop) {
const newProps = { type: "HOC" };
return <div>{prop.render(newProps)}</div>;
// return (props) => <WrappedComponent {...props} {...newProps} />;
}
react的事件机制
阻止合成事件向原生事件的冒泡采用e.nativeEvent.stopImmediatePropagation
useState闭包问题
import React, { useState } from "react";
const Demo1 = () => {
// 这是因为在函数组件中,每次点击add count按钮都会使得count自增一次=>导致Demo1函数重新执行一遍,形成一个新的闭包。每个闭包中的count值是相互独立的。点击alert按钮的这一瞬间形成的闭包中count的值为5,3s之后弹出来的这个值自然也为5。后面再次自增,形成的是新的闭包。互不干扰。
// 而在Class组件中由于都是在this的上下文中改变count的值,而不会形成隔离的闭包,因此,虽然点击alert按钮那一时刻count的值为5,但是随着后面点击add count按钮,count值不断自增。修改的都是this上面的值,3s后弹出的也就是count的最新值了。
let [count, setCount] = useState(0);
const addCount = () => {
setCount(count + 1);
};
const alertCount = () => {
setTimeout(() => {
alert(count);
}, 3000);
};
return (
<div>
<button onClick={addCount}>add Count</button>
<button onClick={alertCount}>alertCount</button>
<div>count: {count}</div>
</div>
);
};
export default Demo1;
父组件调用子组件方法
//子组件
import React, { forwardRef, useImperativeHandle } from "react";
import { Modal } from "./components/children";
const ChildComp = forwardRef(({ value, onChange }, ref) => {
function hah() {
console.log(111);
}
useImperativeHandle(ref, () => ({
hah,
}));
return (
<div style={{ marginTop: 100, width: 300 }} ref={ref} onClick={hah}>
<div style={{ width: "100%", background: "red" }}>112</div>
<Modal>
<div style={{ width: "100%", height: "100%", background: "red" }}>
弹窗内容
</div>
</Modal>
</div>
);
});
export default ChildComp;
// 父组件
import React, { Component, useRef } from "react";
import ChildComp from "./ChildComp";
export default function App() {
const childRed = useRef(null);
function haha() {
childRed.current.hah();
}
return (
<div>
App
<ChildComp ref={childRed} />
<div onClick={haha}>调用子组件hah方法</div>
</div>
);
}
****vue3也是这样再父组件调用子组件方法#####
类组件
// es6 class
// 实例属性的以前的写法
constructor(){
this._count = 0
}
// 新的写法
_count = 0
// 类组件的定义
import React, { Component } from "react";
import Context from "./views/Context";
export default class App extends Component {
//name = "1";
constructor(props) {
super(props);
this.state = {
list: ["中国", "美国"],
};
}
render() {
this.result = this.state.list.map((v, index) => <li key={index}>{v}</li>);
return (
<div>
{this.result}
<Context />
</div>
);
}
}
类组件事件
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this); }
handleClick() { this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn })); }
render() {
return (
<button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
useContext使用流程
//1.新建Context.js
import { createContext } from "react";
export const ImageSizeContext = createContext(500);
//使用
export default function App() {
const [isLarge, setIsLarge] = useState(false);
const imageSize = isLarge ? 150 : 100;
return (
<ImageSizeContext.Provider value={imageSize}>
<label>
<input
type="checkbox"
checked={isLarge}
onChange={(e) => {
setIsLarge(e.target.checked);
}}
/>
Use large images
</label>
<hr />
<List />
</ImageSizeContext.Provider>
);
}
function List() {
const listItems = places.map((place) => (
<li key={place.id}>
<Place place={place} />
</li>
));
return <ul>{listItems}</ul>;
}
function Place({ place }) {
return (
<>
<PlaceImage place={place} />
<p>
<b>{place.name}</b>
{": " + place.description}
</p>
</>
);
}
function PlaceImage({ place }) {
const imageSize = useContext(ImageSizeContext);
return (
<img
src={getImageUrl(place)}
alt={place.name}
width={imageSize}
height={imageSize}
/>
);
}
keep-alive与权限路由实现流程(Router v5版本)
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
Redirect,
} from "react-router-dom";
import Child1 from "./components/Child1.jsx";
import Child2 from "./components/Child2.jsx";
import { saveToken, deleteToToken } from "./utils/storage.js";
import PriviteRoute from "./components/priviteRoute.jsx";
import KeepAlive from "./components/keepAlive.jsx";
function App() {
//保存token
const saveToToken = () => {
saveToken();
};
return (
<div>
<div>
<button onClick={saveToToken}>保存token</button>
<button onClick={deleteToToken}>清除token</button>
</div>
<div>
{/* 定义路由出口 */}
<Router>
<nav>
<Link to="/child1">Link: go to child1</Link>
<Link to="/child2">Link: go to child2</Link>
</nav>
<Switch>
{/* 根组件默认展示,要添加 exact 属性,防止二次渲染 */}
{/* <Route path="/" component={Child1} exact /> */}
{/* 路由重定向 */}
{/* <Redirect from="/" to="/child1" exact /> */}
<Redirect from="/" to="/child1" exact />;
<PriviteRoute path="/child1">
<KeepAlive path="/child1">
<Child1></Child1>
</KeepAlive>
</PriviteRoute>
<Route path="/child2/:id" component={Child2} />
</Switch>
</Router>
</div>
</div>
);
}
export default App;
// 定义(keep-alive)
import React from "react";
import { Route } from "react-router-dom";
export default function KeepAlive({ children, ...rest }) {
return (
<Route
{...rest}
children={(props) => {
// console.log(props.match);
return (
<>
<div style={{ display: props.match ? "block" : "none" }}>
{children}
</div>
</>
);
}}
></Route>
);
}
// 定义权限路由
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { getToken } from "../utils/storage.js";
export default function PriviteRoute({ children, ...rest }) {
// console.log(!!getToken());
return (
<Route
{...rest}
render={() => {
if (!!getToken()) {
return children;
} else {
return (
<Redirect
to={{
pathname: "/child2",
// state: {
// from: location.pathname,
// },
}}
></Redirect>
);
}
}}
></Route>
);
}