react 学习笔记
react 学习笔记
注意事项
React
组件名称必须以大写字母开头React Hook
名称必须以“use”开头
关键技术点总结
- Redux(如类可丝) 状态框架
- hook 函数式组件
- class 类组件
技能点hooks-intro
- 技能点hooks-intro
class
组件componentDidMount
、componentDidUpdate
和componentWillUnmount
5大核心概念
1.组件
2.JSX
3.props & state
4.组件API
5.组件类型
目录
创建项目
# js
create-react-app my-app
# ts
create-react-app react-demo-01-ts --template typescript
组件声明周期
- componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行
- componentDidUpdate()在更新后会被立即调用
- componentWillUnmount() 组件从DOM中移除调用
组件写法
概念:你编写所有的React
代码基本上就是包含许多小组件在内的大组件。
class 写法
class MyComponent extends React.Component {
render() {
return <p>Hello World!<p>;
}
}
function函数式写法(无状态组件)
当然在这样的组件当中你也没有办法使用 setState
方法,也即是说函数式组件没有 state
,所以也可以被称作是无状态组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
组件传值
父组件传子组件
- 通过在子组件写
props
,子组件再从this.props
中获取相应的值
// 父组件
class Parent extends React.Component {
name = "张德帅";
render() {
return (
<Child myProp={this.message} />
);
}
}
// 子组件
class Child extends React.Component {
child_name = this.props.myProp;
render(){
return (
<div>{this.child_name}</div>
)
}
}
子组件向父组件传值
子组件调用父组件通过 props
传入的处理函数,对需要传递的值进行处理
// 父组件
class Parent extends React.Component {
state = {
message:"张德帅"
}
handleMsg(msg){
this.setState({
message:msg
})
}
render() {
return (
<>
{this.state.message}
<Child onMsg={(msg) => this.handleMsg(msg)}></Child>
</>
);
}
}
// 子组件
class Child extends React.Component{
handleClick(){
this.props.onMsg("Hello");
}
render() {
return (
<button onClick={() => this.handleClick()}>Click me</button>
);
}
}
同级传递
状态提升,以父组件作为媒介,让兄弟组件通过父组件进行传递
// 父组件
class Parent extends React.Component {
state = {
message:"张德帅"
}
handleMsg(msg){
this.setState({
message:msg
})
}
render() {
return (
<>
{this.state.message}
<Hello name={this.state.message}></Hello>
<Child onChangeMsg={(msg) => this.handleMsg(msg)}></Child>
</>
);
}
}
// 子组件 -- 发起改变的组件
class Child extends React.Component{
render() {
return (
<button onClick={() => this.props.onChangeMsg("朱大常")}>Click me (朱大常)</button>
);
}
}
// 子组件 被改变的组件
class Hello extends React.Component{
render(){
return <h1>hello {this.props.name}</h1>
}
}
通过refs-转发-子组件向父组件传值
class Parent extends React.Component {
myRef = React.createRef();
handleClickRef(msg) {
this.myRef.current.innerText = msg;
}
render() {
return (
<>
<RefsValue ref={this.myRef} handleClickRef={this.handleClickRef.bind(this)}></RefsValue>
</>
);
}
}
// 子组件
const RefsValue = React.forwardRef((props, ref) => {
return (<>
<span ref={ref}>hello</span>
<button
onClick={() => props.handleClickRef('world')}
>Change</button>
</>);
});
孙组件传递context
第一步:在src创建文件 context.js(任意名)
context.js 内容如下
import { createContext } from "react";
export default createContext();
第二步:引用 使用 Provider包裹组件
// 父组件
import * as React from "react";
import Child from "./component/Child/Child";
import contextName from "./context/context";
class App extends React.Component {
render(){
return (
<>
<contextName.Provider value="dark">
<Child></Child>
</contextName.Provider>
</>
)
}
}
export default App;
中间组件
// 中间组件
import * as React from "react";
import Child2 from "../Child2/Child";
class Child extends React.Component{
render() {
return (
<>
<h1>Child----0</h1>
<Child2></Child2>
</>
);
}
}
export default Child
孙组件使用
this.context
获取
// 孙组件
import React from "react";
import contextName from "../../context/context";
class Child2 extends React.Component{
static contextType = contextName;
render(){
return (
<div>
<h1>child --- 1</h1>
<button theme={this.context}>{this.context}</button>
</div>
)
}
}
export default Child2
组合式组件props.children
概念:vue中的slot插槽一样
class App extends React.Component {
constructor(props){
super(props);
this.state = {
name:"张德帅"
}
}
render(){
return (
<>
<SplitPane left={test1(this.state)} right={test2()}></SplitPane>
</>
)
}
}
function test1(props111){
return (
<p>test-left {props111.name}</p>
)
}
function test2(){
return(
<p>test-right</p>
)
}
Hook
Hook 是 React 16.8 它可以让你在不编写 class
的情况下使用 state
以及其他的 React 特性
useLayoutEffect
但它会在所有的 DOM
变更之后同步调用 effect
。可以使用它来读取 DOM
布局并同步触发重渲染
总结:
- 作用 例如测量布局
- useLayoutEffect 相比 useEffect,通过同步执行状态更新可解决一些特性场景下的页面闪烁问题。
- useEffect 可以满足百分之99的场景,而且 useLayoutEffect 会阻塞渲染,请谨慎使用。
useEffect
你可以把 useEffect Hook
看做 componentDidMount
,componentDidUpdate
和 componentWillUnmount
这三个函数的组合。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
useState
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0); // 第一个是 当前状态 第二个是让你更新它的函数
const [todos, setTodos] = useState([{ test: "张德帅" }]);
return (
<div>
<p>you clicked {count} times</p>
<p>you name {todos[0].test}.</p>
<button
onClick={() => {
setCount(count + 1);
}}
>
click me
</button>
<button
onClick={() => {
setTodos((data) => {
return [{ test: "asdqwe" }];
});
}}
>
change name
</button>
</div>
);
}
export default Counter;
useContext
useContext(MyContext)
相当于 class
组件中的 static contextType = MyContext
或者 <MyContext.Consumer>
第一步 创建文件 context.js 和 class 组件一样
context.js 内容如下
import { createContext } from "react";
export default createContext();
第二步 父组件使用Provider包裹 然后使用value 传值
import * as React from "react";
import ThemeContext from "./context/context";
import Child01 from "./component/Child01";
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
function App(){
return (
<ThemeContext.Provider value={themes.dark}>
<Child01></Child01>
</ThemeContext.Provider>
)
}
export default App;
第三步 中间组件
import Child02 from "../Child02/index";
function child01(){
return (
<Child02></Child02>
)
}
export default child01;
第四步 孙组件 使用 useContext 获取值
import React, {useContext} from "react";
import ThemeContext from "../../context/context";
function Child02(){
const theme = useContext(ThemeContext);
return (
<button style={{background:theme.background, color:theme.foreground}}>I am styled by theme context!</button>
)
}
export default Child02;
useReducer
useState
的替代方案,它接收一个形如 (state, action) => newState
的 reducer
(瑞丢蛇-减速器),并返回当前的 state
以及与其配套的 dispatch
(滴丝吧齐-调度) 方法
useReducer demo01
import React, {useReducer} from "react";
const initialState = {count:0};
function reducer(state, action){
switch(action.type){
case "increment":
return {count:state.count + 1}
case "decrement":
return {count:state.count -1};
default:
throw new Error();
}
}
function Reducerdemo01(){
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
count:{state.count}
<button onClick={() => dispatch({type:"increment"})}>+</button>
<button onClick={() => dispatch({type:"decrement"})}>-</button>
</>
)
}
export default Reducerdemo01;
useReducer demo02
import React, { useReducer } from "react";
const initState = {
name:"",
pwd:"",
isLoading:false,
}
function loginReducer(state, action){
switch(action.type){
case "login":
return {
...state,
isLoading:true,
name:"zhangds"
}
case "success":
return{
...state,
isLoading:false,
name:"zhangds---ok",
pwd:"123a"
}
case "error":
return {
...state,
isLoading: false,
name:"zhangds---error"
}
default:
return state;
}
}
function Login(){
const [state, dispatch] = useReducer(loginReducer, initState);
const login = () =>{
dispatch({type:"login"});
setTimeout(() =>{
dispatch({type:"success"});
}, 2000)
}
return (
<>
<p>name:{state.name}</p>
<p>pwd:{state.pwd}</p>
<p>isLoading:{state.isLoading ? "真" :"假"}</p>
<button onClick={login}>登录</button>
</>
)
}
export default Login;