React.createElement(type,props,children)
返回一个虚拟dom
-
JSX
JSX=JS+XML
JSX是一种语法糖,可以为js添加XML的语法扩展
!!!: JSX的本质:将XML其转化为React.createElement,然后转化成虚拟DOM。在17之后直接编译成虚拟DOM
-
React 17 和 17 之前的差异:
-
在 React 17 新增了 JSX-runtime,可以将 JSX 直接编译成 虚拟DOM
-
在 React 17 之前,JSX 将会被编译成 React.createElement();
在 17 及之后,如果模块中,只用到了 React 的 JSX ,则不需要引入 React 依赖.
-
state
在React中想要更新状态,必须调用组件的setState 方法
- setState 会进行浅合并,所以必须给定所有需要替换的state
- setState批量更新时是异步操作,单独更新时是同步操作
-
父子组件通信
-
父传子:在父组件中注册子组件处传入信息,然后在子组件中用props接收。
-
子传父:子组件调用从父组件传过来的回调函数,然后引起父组件变化。
-
context
- context需要利用createContext()来创建,类似vue中的eventBus。
import {createContext} from "react"; const context = createContext(); const {Provider,Consumer} = context; export {Provider,Consumer} export default context;
-
在父组件中用Provider来给其子孙组件传递信息。
import { Component } from "react"; import Contatiner from "./container"; import context,{Provider} from "./context"; console.log(context); class App extends Component { state = { showName: "friend", nub: 1 } render() { const {showName,nub} = this.state; return <div> <Provider value={{ showName,nub }} > <Contatiner /> </Provider> </div> } } export default App;
-
在其子孙组件中可以通过Consumer或者
static contextType=context
来接收import { Component } from "react"; import {Consumer} from "./context"; export default class Nub extends Component { render(){ return <Consumer> {({nub})=>{ //console.log(context); return <p>{nub}</p> }} </Consumer> } }
import { Component } from "react"; import context from "./context"; class Name extends Component { static contextType = context; render(){ const {showName} = this.context; return <> <p>{showName}</p> </> } } export default Name;
-
-
受控组件和非受控组件
-
受控组件:类似于 vue 中,v-model
当我们需要在表单控件之外,获取表单的内部状态时,可以将表单的内部状态和组件的状态进行绑定,这种情况下,组件的状态改变表单的状态也会随之改变,表单的状态改变,组件的状态也会随之改变,我们称之为 受控组件
在使用受控组件时,必须添加 onChange 回调,在回调中监听 表单的状态改变,然后更新组件状态
<input type="text" value={val} onChange={({target})=>{ this.setState({ val:target.value }) }} />
-
非受控组件:
当我们想要设置,表单控件的初始值时,如果直接使用 value 或者 checked 的话,react 会认为我们想要实现的是 受控组件,这是就会提示我们添加 onchange 回调,否则 控件会变成只读的。这时可以使用 defaultValue 或 defaultChecked
<input type="text" defaultValue="你爱写啥写啥" />
-
类组件
-
生命周期 react16.4
-
挂载阶段
- constructor(props) 组件初始化
- static getDerivedStateFromProps(props,state) 将父组件传过来的 props 中内容关联到子组件的 state 中 。 注意 this 问题
- render 构建当前组件的虚拟DOM
- componentDidMount 组件挂载完成 - 通常在该生命周期函数,进行副作用处理
-
更新阶段(1.调用setState;2.父组件更新引起子组件更新;3.调用forceUpdate进行更新)
- static getDerivedStatefromProps(props,state)
- shouldComponentUpdate(nextProps,nextState) -- 判断是否更新 return true 组件更新 || false 不在继续执行更新流程
- render()
- getSnapshotBeforeUpdate -- 获取更新前的DOM快照,该函数执行时react已经完成了新老DOM对比,即将更新真实DOM,我们可以获取更新前的DOM,用于和更新后的DOM进行对比。该方法必须配合 componentDidUpdate 一块使用,该方法的返回值,会变成 componentDidUpdate 的 pervDOM 参数
- componentDidUpdate(prevProps,prevState,prevDOM) -- 组件更新完成 处理副作用(请求)
-
卸载阶段
componentWillUnmount 组件即将卸载
-
-
pureComponent(可以只更新修改项,不更新未修改项)
pureComponent会实现一个对props和state进行浅层比较,相当于Component使用了shouldComponentUpdate(nextProps,nextState).
函数组件
-
innerHTML
let data = `<div> <h2>我想给大家一个大福利</h2> <p>大家想要吗?</p> </div>`; // function App(props) { // return <div dangerouslySetInnerHTML={{ // __html:data // }}></div> // } function App(props) { return <div ref={node=>node.innerHTML=data}></div> } export default App;
-
ref
- 当ref中是函数时,组件更新或挂载完成后执行该函数,并将该ref对象 传递(很少使用)
- 当ref接收的是对象,那么将该对象存入ref中
-
children(类似于插槽)
在父组件中注册子组件的位置,在子组件标签中间的内容,可以在子组件中通过props.children接收
// 父组件 import Child from "./child"; function App(props) { return <div> <Child info={"这是info属性"}> <p>这是通过 children 属性传递过来的信息</p> <p>这是通过 children 属性传递过来的第二条信息</p> {()=>{ return <h3>随便来点啥</h3> }} </Child> </div> } export default App;
// 子组件 function Child(props) { console.log(props); return <div> <h2>子节点</h2> {props.children[0]} {props.children[1]} {props.children[2]()} </div> } export default Child;
-
hooks(用来解决函数组件中的逻辑复用问题)
import { useState } from "react"; function App() { const [nub,setNub] = useState(0); const [val,setVal] = useState("初始值"); return <div> <p>{nub}</p> <button onClick={()=>{ setNub(nub + 1); }}>递增</button> <p>{val}</p> <input type="text" value={val} onChange={({target})=>{ setVal(target.value); }} /> </div> } export default App;
-
useState
-
const [state,setState]=useState("初始值"),其中setState不会进去浅合并操作。如果数据是state内的数据,需要进去合并操作。
function App() { const [state,setState] = useState({ nub: 1, count: 1 }); const {nub,count} = state; return <> <p>{nub}</p> <button onClick={()=>{ setState({ ...state, nub: nub + 1 }); }}>递增nub</button> <p>{count}</p> <button onClick={()=>{ setState({ ...state, count: count + 1 }); }}>递增count</button> </>; }
-
useState生成的数据是数组,所在在使用时要保证其调用顺序,不能使用if,for,while等循环语句
-
如果state是引用类型,那么setState传入的是原有引用,数据不更新,需要浅复制一个新引用
-
const addMessage = (user, message) => { // 使用 useState 时,如果数据是引用类型,并且 setState 时,传入的还是原有引用,组件不更新 let newData = data.data; newData.push({ id: Date.now(), user, message, checked: false }); setData({data:newData}); };
-
useEffect() 副作用函数,用来取代生命周期函数
useEffect(()=>{// 副作用函数 *** return ()=>{// 返回函数 *** } },[依赖参数])
-
挂载阶段:执行顺序从上到下。碰到useEffect就将其副作用函数传入一个链表,当组件挂载完成之后,执行副作用函数。并将副作用函数的返回函数插入新的链表。
-
更新阶段:执行顺序从上到下。如果碰到useEffect就将其副作用函数传入一个链表,在组件更新之后,找出挂载阶段的返回函数准备执行,如果以来参数改变,返回函数就执行。接着执行更新阶段传入的副作用函数,执行时也要判断依赖参数是否发生了改变。最后将新的返回函数传入新的链表。
-
卸载阶段:组件即将卸载时,找到更新阶段的组件对应的返回函数,依次执行
-
依赖为空数组:副作用函数在组件挂载完之后执行,返回函数在组件即将卸载时执行
useEffect(()=>{ console.log("组件挂载完之后执行"); return ()=>{ console.log("组件即将卸载时执行"); } },[]);
-
没有依赖:组件会在挂载或更新完成之后都会执行
-
-
useRef()
- 和createRef类似,都可以用来关联实例
- useRef(initialValue) :当useRef中存的是一条数据时,该ref中的数据不会随着组件更新而更新,除非手动传入新的数据。所以可以用来做跨组件之间的更新阶段的数据传递。
-
自定义hook
-
自定义hook必须使用use开头来命名
-
当有重复节点时,可以使用自定义hook
-
通过props来传递可变参数
import { useState } from "react"; function useInputText(initialState="",props={}) { const [val,setVal] = useState(initialState); const input = <input type="text" value={val} {...props} onChange={({target})=>{ setVal(target.value); }} /> return [val,input,setVal] } function useTextarea(initialState="",props={}) { const [val,setVal] = useState(initialState); const input = <textarea value={val} {...props} onChange={({target})=>{ setVal(target.value); }} /> return [val,input,setVal] } export {useInputText,useTextarea}
-
-
useMemo()
useMemo会有一个返回值或返回函数,可以用来监听依赖参数的变化。
function Child() { const [nub,setNub] = useState(1); const [count,setCount] = useState(1); const count2 = useMemo(()=>{ // 返回一个值 console.log("memo"); return count*10; },[count]); const clickHandler = useMemo(()=>()=>{ // 返回一个函数 alert("点击"); },[]); return <> <p>{nub}</p> <button onClick={()=>{ setNub(nub + 1); }}>递增nub</button> <p>{count}</p> <p>{count2}</p> <button onClick={()=>{ setCount(count + 1); }}>递增count</button> <button onClick={clickHandler}>点击</button> </>; }
-
useCallback()
useMemo的返回值是一个函数时,可以使用useCallback()来替换,useCallback(fn)的参数一一个函数,直接返回,根据依赖参数变化进行触发
function Child() { const clickHandler = useCallback(()=>{ alert("点击") },[]) return <> <button onClick={clickHandler}>点击</button> </>; }
-
memo 高阶组件,会返回一个新的组件
-
第一个参数是传入组件
-
第二个参数是一个函数,用来判断前后数据是否一致,如果不一致,则进行更新
import { memo} from "react"; function Li({data,setChecked,editMessage}) { *** } const NewLi = memo(Li,(props,nextProps)=>{ return props.data === nextProps.data;// true 不更新 Li,false 更新 li }) export default NewLi;
-
-