快速学习React(一):基本内容

React

基本语法

1. 在React中一个组件组件就是一个function,通过return的方式,返回对应的内容。jsx或者tsx是js 或 ts 结合 HTML的语法,React中的差值语法是放在{}中,Vue是放在{{}}中。

function App() {
​
   const divContent = '标签内容'
   const divTitle = '标签标题'
​
   return (
       // 或者使用这种方式,就类似于Vue中template
       <>
           <div className="App">
               {/*只能返回一个根div*/}
               wangxing
           </div>
       </>
   );
 }
  1. 基本的条件判断。

function App() {
​
   let divContainer :any = null;
   const flag = true
    if(flag){
        divContainer = <span>我是span</span>
    }else{
        divContainer = <p>我是p</p>
    }
​
   return (
       // 或者使用这种方式,就类似于Vue中template
       <div className="App" >
           {divContainer}
       </div>
   );
}
  1. 与js结合:Map是有返回值的,所以使用map,结合html语法,非常方便的就实现了对应的功能。

function App() {
​
   const list = [
       {
           id:1001,
           name:'wangxing'
       },
       {
           id:1002,
           name: 'lv'
       }
   ]
​
​
    const divContent = list.map(item => <li key={item.id}>{item.name}</li>)
​
   return (
       // 或者使用这种方式,就类似于Vue中template
       <div className="App" >
           {divContent}
       </div>
   );
}
  1. Fragment

比如这里的map方法中,想要一次映射两个li,首先想到的可能是<></>,但是这个标签不能放对应的属性,比如key,可以使用react提供的一个Fragment标签,这个可以解决不能放属性的问题,像template。

import {Fragment} from "react";
​
function App() {
​
    const list = [
        {
            id:1001,
            name:'wangxing'
        },
        {
            id:1002,
            name: 'lv'
        }
    ]
​
​
     const divContent = list.map(item =>
         <Fragment key={item.id}>
             <li>{item.name}</li>
             <li>------------------------</li>
         </Fragment>
     )
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <div className="App" >
            {divContent}
        </div>
    );
 }
  1. useState

const [data,setData] = useState(data) ,是用setData的时候可以先展开原来的对象,在放上先要修改的属性,注意这里的setData中可以放上{},也可以放[],毕竟这两个都是对象。

const [data,setData] = useState([
    {
        id:1,
        name:'wangxing'
    },
    {
        id:2,
        name:'xiaoming'
    },
    {
        id:3,
        name:'xiaoli'
    },
])
​
​
let id :number = 3
​
const dataList  = data .map(
    item => <li key={item.id}>{item.name}</li>
)
​
function handleClick(e:any):void {
​
    //是直接换掉整个对象
​
    setData([
        ...data,
        {
            id: ++id,
            name :'heieh'
        }
    ])
}

这...data和{}放的顺序不同,渲染出来的列表也不同,因为数组是有顺序的,数组的操作,决定的渲染的操作,react和ts的结合非常好。

function handleClick(e:any):void {
​
    //是直接换掉整个对象
​
    setData(
        data.filter(item => item.id !== 2)
    )
}

组件通讯和插槽

dom

属性展开

function App() {
​
​
    const divData = {
        className:"App-header",
        style:{
            backgroundColor:'blue',
            width:'100%',
            height:'100%'
        }
    }
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <div className="App" >
            <div {...divData}>
                ddd
            </div>
        </div>
    );
 }

自定义组件

组件通讯

function Article({title,content}:any){
    return (
        <div className="article">
            <h2>{title}</h2>
            <span>{content}</span>
        </div>
    )
}
export default function App() {
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <>
            <Article
               title="标签1"
                content="内容1"
            />
            <Article
               title="标签2"
               content="内容2"
            />
            <Article
               title="标签3"
               content="内容3"
            />
        </>
    );
 }

展开属性

function Detail(props:any){
​
    return (
        <>
            <span>{props.content}</span>
            <p>{props.active ? '展示' : '隐藏'}</p>
        </>
    )
}
​
​
function Article({title,detailData}:any){
​
    console.log(title);
    return (
        <div className="article">
            <h2>{title}</h2>
            <Detail {...detailData}/>
        </div>
    )
}
​
​
export default function App() {
​
    //请求过来的数据
    const articleData =   {
        title:'标题',
        detailData : {
            content:'内容',
            active :true
        }
    }
​
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <>
            <Article
                {...articleData}
            />
​
        </>
    );
 }

插槽

import {ReactNode} from "react";
​
function List({children}: {children: ReactNode}) {
    return (
        <ul>
            {children}
        </ul>
    )
}
​
export default function App() {
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <>
            <List>
                <li>列表项</li>
                <li>列表项</li>
                <li>列表项</li>
            </List>
        </>
    );
}

 

如果出来插槽的内容外,还有别的属性怎么办???直接写上即可,因为在React中没有插槽这个概念,或者说他是一个特殊的props,放在了children中。

import {ReactNode} from "react";
​
function List({children,title = '默认标题',footer= <div>默认内容</div>}: {children: ReactNode,title?: string,footer?: ReactNode}) {
    return (
        <>
            <div>
                {title}
            </div>
            <ul>
                {children}
            </ul>
​
            {footer}
        </>
    )
}
​
export default function App() {
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <>
            <List
                title='list1'
                footer={<span>底部内容1</span>}
            >
                <li>列表项1</li>
                <li>列表项1</li>
                <li>列表项1</li>
            </List>
            <List
                title='list2'
                footer={<span>底部内容2</span>}
            >
                <li>列表项2</li>
                <li>列表项2</li>
                <li>列表项2</li>
            </List>
        </>
    );
}

 

子组件向父组件传值,和Vue的emit类似,父组件给子组件提供一个方法,子组件接收到,在适合的时候调用这个方法即可,不过也是通过Props来进行的。

import {ReactNode, useState} from "react";
​
​
​
function Detail({onActive}:any){
​
    const [isShow,setShow] = useState(true)
​
​
    function handleClick(){
        setShow(!isShow)
        onActive(isShow)
    }
​
    return (
        <div>
            <p
                style={{display: isShow ? "block" : "none"}}
            >
                Detail的内容
            </p>
            <button onClick={handleClick}>
                按钮
            </button>
        </div>
    )
}
​
export default function App() {
​
    function handleActive(status:boolean){
        console.log('当前组件的状态:',status)
    }
​
    return (
        // 或者使用这种方式,就类似于Vue中template
        <>
           <Detail
               onActive={handleActive}
​
           />
​
        </>
    );
}

useContext

使用Context完成不同层级数据的渲染。

import React, {useContext} from "react";
​
function Select({children}: any) {
​
    const level :number = useContext(LevelContext);
​
    return (
        <section className="selection">
            <LevelContext.Provider value={level + 1}>
                {children}
            </LevelContext.Provider>
        </section>
    )
}
function Heading({children}: any) {
​
    const level :number = useContext(LevelContext);
​
    switch (level) {
        case 1:
            return <h1>{children}</h1>
        case 2:
            return <h2>{children}</h2>
        case 3:
            return <h3>{children}</h3>
        case 4:
            return <h4>{children}</h4>
        default:
            throw Error(`Unknown level: ${level}: ${JSON.stringify(children)}`)
    }
}
​
const LevelContext = React.createContext<number>(1)
​
export default function App(){
    return (
        <div>
            <Select>
                <Heading >
                    <Select>
                        <Heading >Title</Heading>
                        <Heading >Title</Heading>
                        <Heading >Title</Heading>
                    </Select>
                </Heading>
                <Heading >Title</Heading>
                <Heading >Title</Heading>
                <Heading >
                    <Select>
                        <Heading >Title</Heading>
                        <Heading >Title</Heading>
                        <Heading >
                            <Select>
                                <Heading >Title</Heading>
                            </Select>
                        </Heading>
                    </Select>
                </Heading>
                <Heading >Title</Heading>
                <Heading >Title</Heading>
            </Select>
        </div>
    )
}

 

React Hooks

Reducer

统一管理状态的操作方式

import {useReducer, useState} from "react";
​
function countReducer(state:any,action:{type:string}){
    switch(action.type){
        case "Increment":
            return state + 1;
        case "Decrement":
            return state - 1;
        default:
            throw new Error(`Unknown action type ${action.type}`);
    }
}
​
​
export default function App (){
​
    const [state, dispatch] = useReducer(countReducer, 0)
​
    const handleIncrement = ()=> dispatch({type:"Increment"})
​
    const handleDecrement = ()=> dispatch({type:"Decrement"})
​
    return (
        <div className="App">
            <button onClick={handleIncrement}>+</button>
            <span>{state}</span>
            <button onClick={handleDecrement}>-</button>
        </div>
    )
​
}

useRef

useRef中的值不会随着组件的更新而发生改变。

import {useRef, useState} from "react";
​
export default  function App(){
​
    const [count,setCount] = useState(0)
​
    const preCount:React.MutableRefObject<number | undefined> = useRef()
​
    function handleClick(){
        preCount.current = count
        setCount(count + 1)
    }
​
    return (
        <div>
            <p>最新的count:{count}</p>
            <p>上次的count:{preCount.current}</p>
            <button onClick={handleClick}>增大Count</button>
        </div>
    )
}

这里的就和Vue中的ref很像,可以拿到对应的组件。

import {useRef, useState} from "react";
​
export default  function App(){
    const inputRef:any = useRef(null)
​
    function handleClick() {
        inputRef.current.focus()
    }
​
    return (
        <div>
            <input type={'text'} ref={inputRef}/>
            <button onClick={handleClick}>click</button>
        </div>
    )
}

访问子组件内部功能

import {forwardRef, useImperativeHandle, useInsertionEffect, useRef, useState} from "react";
​
const Child = forwardRef((props, ref) => {
​
    useImperativeHandle(ref, () => ({
        // 暴露给父组件的方法
        handleClick() {
            console.log('子组件的方法被调用了')
        }
    }))
​
    return (
        <div>子组件</div>
    )
})
​
​
export default  function App(){
​
    const childRef:any = useRef(null)
​
    function handleClick() {
        childRef.current.handleClick()
    }
​
    return (
        <div>
            <Child ref={childRef} />
            <button onClick={handleClick}>click</button>
        </div>
    )
}

useEffect

副作用函数

import {useEffect, useReducer, useState} from "react";
​
function countReducer(state:any,action:{type:string}){
    switch(action.type){
        case "Increment":
            return state + 1;
        case "Decrement":
            return state - 1;
        default:
            throw new Error(`Unknown action type ${action.type}`);
    }
}
​
​
export default function App (){
​
    const [state, dispatch] = useReducer(countReducer, 0)
​
    const handleIncrement = ()=> dispatch({type:"Increment"})
​
    const handleDecrement = ()=> dispatch({type:"Decrement"})
​
​
    useEffect(()=>{
        console.log("state changed",state)
    },[])  // 第二个参数是依赖项,当依赖项发生变化时,useEffect才会执行
​
    return (
        <div className="App">
            <button onClick={handleIncrement}>+</button>
            <span>{state}</span>
            <button onClick={handleDecrement}>-</button>
        </div>
    )
​
}

 

useMemo 和 useCallBack

父组件重新渲染,会有导致子组件也进行重新渲染的问题。当父组件刷新的时候,会进行相应的判断,比如父传子的props有没有发生改变?如果没有发生改变,即使父组件重新渲染,子组件也不会重新渲染,这个时候只要传给子组件的数据不发生改变即可。

useMemo(用于状态)

import React, {useState} from "react";
​
function Child({value}:any) {
    function computeValue(){
        console.log(value)
        return <span>{value}</span>
    }
​
    return computeValue()
}
​
export default function App() {
​
    const [value,setValue] = useState(0)
​
    const [content,setContent] = useState("wangxing")
​
    function handleContent(){
        setContent(content + content)
    }
​
    return (
​
​
        <div className="App">
            <div>
                {content}
            </div>
​
            <button onClick={handleContent}>改变内容</button>
​
            <Child value={value} />
​
            <button onClick={()=>setValue(value+1)}>增加数据</button>
        </div>
    )
}

这个例子来说,如果不修改count,修改别的内容,触碰到页面刷新了,也会调用computeValue函数。

import React, {useMemo, useState} from "react";
​
function Child({value}:any) {
    const computeValue = useMemo(() =>{
        console.log(value)
        return <span>{value}</span>
    },[value])
​
    return computeValue
}
​
export default function App() {
​
    const [value,setValue] = useState(0)
​
    const [content,setContent] = useState("wangxing")
​
    function handleContent(){
        setContent(content + content)
    }
​
    return (
​
​
        <div className="App">
            <div>
                {content}
            </div>
​
            <button onClick={handleContent}>改变内容</button>
​
            <Child value={value} />
​
            <button onClick={()=>setValue(value+1)}>增加数据</button>
        </div>
    )
}

这种方式就可以解决问题。

useCallback(用于方法)

import React, {useMemo, useState} from "react";
​
function Child({onClick}:any) {
    console.log("Child渲染")
​
    const handleClick = () => {
        onClick()
    }
    return <>
        <button onClick={handleClick}>子组件</button>
    </>
​
}
​
export default function App() {
​
    const [content,setContent] = useState("wangxing")
​
    function handleContent(){
        setContent(content + content)
    }
​
    const handleData = () => {
        console.log("handleData----father")
    }
​
    return (
        <div className="App">
            <div>
                {content}
            </div>
            <button onClick={handleContent}>改变内容</button>
            <Child onClick={handleData} />
        </div>
    )
}

上面的代码,点击了改变内容的按钮(父组件中的),父组件重新渲染,也会导致Child组件进行重新渲染,使用React的memo()可以把子组件变成一个记忆组件,只要确保父给子的函数不会发生变化,子组件就不会有重新渲染的问题,问题的关键就变成如何确保父组件重新渲染,对应的函数也不发生改变----> useCallBack.

import React, {useMemo, memo, useState, useCallback} from "react";
​
const Child = memo(function ({onClick}:any) {
    console.log("Child渲染")
​
    const handleClick = () => {
        onClick()
    }
    return <>
        <button onClick={handleClick}>子组件</button>
    </>
​
})
​
export default function App() {
​
    const [content,setContent] = useState("wangxing")
​
    function handleContent(){
        setContent(content + content)
    }
​
    const handleData = useCallback(() => {
        console.log("handleData----father")
    },[])// [] 是一个依赖数组,如果依赖数组为空,则不会重新渲染
​
    return (
        <div className="App">
            <div>
                {content}
            </div>
            <button onClick={handleContent}>改变内容</button>
            <Child onClick={handleData} />
        </div>
    )
}

上面的代码做了两点:

  1. Child变成记忆组件

  2. handleData方法使用useCallback包裹,使其不会发生改变。

笔记内容的视频参考:

40分钟学会React18组件通信与插槽 可能是你学会React最好的机会 前端开发必会框架 无废话精品视频_哔哩哔哩_bilibili

 

30分钟学会React18核心语法 可能是你学会React最好的机会 前端开发必会框架 无废话精品视频_哔哩哔哩_bilibili20分钟学会React Hooks 前端开发必看 AI编程工具 CodeGeeX 体验_哔哩哔哩_bilibili 

 

  • 20
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值