React学习记录心得笔记(含代码)

89 阅读8分钟

JSX

JSX 使用 大括号{}语法

1.引号传递字符串

<!-- function App() { return ( <div className="App"> this is app {'hello'} </div> ); } ` -->

2.使用 javasript 变量

<!--
const num=100;
function App() {
  return (
    <div className="App">
      this is app

      {num}
    </div>
  );
}

 -->`

3.函数调用和方法调用

<!--
function getName(){
  return 'jack';
};
function App() {
  return (
    <div className="App">
      {getName()}
    </div>
  );
}
 -->
 <!-- 
 function App() {
  return (
    <div className="App">
      {new Date().getDate()}
    </div>
  );
}
 
  -->

4.使用 javasript 对象

<!--
function App() {
  return (
    <div className="App">
      {/* {new Date().getDate()} */}
      <div style={{color:'red'}}>this is div</div>
    </div>
  );
}

 -->

JSX 实现列表渲染 map 方法

加唯一 key 属性


<!--

const list=[
  {id:1001,name:'jack'},
  {id:1002,name:'tom'},
  {id:1003,name:'mike'}
]
function App() {
  return (
    <div className="App">
      {/* {new Date().getDate()} */}
      <div style={{color:'red'}}>列表渲染</div>
      <div style={{}}>{list.map(item=><li key={item.id}>{item.name}</li>)}</div>
    </div>
  );
}
 -->

条件渲染 逻辑与运算符·三元表达式

1.逻辑与运算符&&

适用于 1 对 1 条件渲染

2.三元表达式适用于 1 对多

三元表达式适用于 1 对多条件渲染

<!--

const flag=true;
function App() {
  return (
    <div className="App">
      <div style={{color:'red'}}>条件渲染</div>
      <div style={{}}>{flag && <span>hello</span>}</div>
      <div style={{}}>{flag ? <span>true</span> :<span>false</span> }</div>
    </div>
  );
}
 -->

复杂条件渲染

<!-- 形式1 -->
<!--
const num=1;
const getNum=()=>{
  if(num===0){
    return <div>我是0</div>
  }
  else if(num===1){
    return <div>我是1</div>
  }
  else{
    return <div>我是2</div>
  }
}
function App() {
  return (
    <div className="App">
      <div style={{color:'red'}}>复杂条件渲染</div>
      <div style={{}}>{getNum()}</div>

    </div>
  );
}
 -->
//子组件根据 ishow 属性进行条件渲染 if+return
<!-- function Show({ content, isshow }) {
  if (isshow) {
    return( <div >
      <h3>{content}</h3>
    </div>)

  }
  return null;
}
// 父组件
export default function Profile() {
  return (
    <div>
      <Show
        isshow={ true}
        content={"你好呀"}

      >

      </Show>
      <Show
        isshow={ false}>

      </Show>
    </div>
  );
} -->

事件绑定

on+事件名称={事件处理程序} 驼峰命名规范

<!--
const num=0;
function App() {
  const addClick=()=>{
    console.log(num);
  }
  return (
    <div className="App">
      <div style={{color:'red'}}>事件绑定</div>
      <button onClick={addClick}>点击</button>
      {/* <div style={{}}>{getNum()}</div> */}

    </div>
  );
}
 -->

事件对象 e

<!--
function App() {
  const addClick=(e)=>{
    console.log("被点击了",e);
  }
  return (
    <div className="App">
      <div style={{color:'red'}}>事件绑定</div>
      <button onClick={addClick}>点击</button>
      {/* <div style={{}}>{getNum()}</div> */}

    </div>
  );
}
 -->

传递自定义参数 事件绑定的位置改成箭头函数的写法

<!--
function App() {
  const addClick=(name)=>{
    console.log("被点击了",name);
  }
  return (
    <div className="App">

      <button onClick={ () => addClick('wyz') }>点击</button>

    </div>
  );
}
 -->

既要参数也要事件对象

<!--

function App() {
  const addClick=(name,e)=>{
    console.log("被点击了",name,e);
  }
  return (
    <div className="App">
      <div style={{color:'red'}}>React</div>
      <button onClick={(e)=>addClick('wyz',e)}>点击</button>
      {/* <div style={{}}>{getNum()}</div> */}

    </div>
  );
}
 -->

react组件

首字母大写的函数 箭头函数也可以

<!--
const ZuJian=()=>{
  return(
    <div><h1>
      我是一个组件
      </h1></div>
  )
}


function App() {
  return (
    <div className="App">
      <div style={{color:'red'}}>React</div>

      使用组件

      {/* 成对 */}
      <ZuJian></ZuJian>
      {/* 自闭和 */}
      <ZuJian/>

    </div>
  );
}
 -->

父与子组件之间属性传值

第一种 props 传值

<!--
### 子组件
function Avator({ person }) {
return (

<div>
<h2>Katsuko Saruhashi</h2>
<img
        className="avatar"
        alt={person.one}
        width={70}
        height={70}
      />
<ul>
<li>
<b>Profession: </b>
{ person.two}
</li>
<li>
<b>Awards: 2 </b>
({ person.three})
</li>
<li>
<b>Discovered: </b>
{ person.four}
</li>
</ul>

     </div>

);
}

-->


<!--
### 父组件
export default function Gallery() {
return (

<div>
<h1>Notable Scientists</h1>
<h2>Maria Skłodowska-Curie</h2>
<img
className="avatar"

          alt="Maria Skłodowska-Curie"
          width={70}
          height={70}
        />
        <ul>
          <li>
            <b>Profession: </b>
            physicist and chemist
          </li>
          <li>
            <b>Awards: 4 </b>
            (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal)
          </li>
          <li>
            <b>Discovered: </b>
            polonium (chemical element)
          </li>
        </ul>

      <Avator
        person={
          {
            one: "Katsuko Saruhashi",
            two: " geochemist",
            three:"Miyake Prize for geochemistry, Tanaka Prize",
            four:" a method for measuring carbon dioxide in seawater"

          }

      }


      ></Avator>
    </div>

);
}

-->

第二种

上述 Avator 单独写一个文件并暴露,父组件文件再引用:传参注意不要忘记子组件函数声明写接收父组件的参数名称

第三种

直接将内容嵌套在标签中,通过{children}赋值到子组件

<!-- 
子组件


function Card({ children }) {
return (

<div className="card">
<div className="card-content">
{children}
</div>
</div>
);
}

父组件
export default function Profile() {
return (

<div>
<Card>
<h1>Photo</h1>
<img
          className="avatar"
          src="https://i.imgur.com/OKS67lhm.jpg"
          alt="Aklilu Lemma"
          width={100}
          height={100}
        />
</Card>
//传的内容为 children
<Card>
<h1>About</h1>
<h4>Aklilu Lemma was a distinguished Ethiopian scientist who discovered a natural treatment to schistosomiasis.</h4>
</Card>
</div>
);
}

 -->

父与子组件之间属性传值

核心思路:子组件中调用父组件的函数并传递参数 前提是父组件把函数传给子组件

<!--

//子组件

function Son({ onMsy}) {
  const sonMsg = "this is son"

  return (

    <div>
      <button onClick={()=>onMsy(sonMsg)}>子传父</button>
    </div>
  )

}

//父组件

export default function App() {

  const getMsg = (msg) => {
    console.log(msg);
  }
  return (
    <div>
      <Son onMsy={ getMsg}></Son>
  </div>
  )
}
-->

兄弟组件通信(状态提升)

实现思路:使用状态提升机制,通过父组件进行兄弟组件之间的数据传递

状态提升:兄弟组件使用共同的父类作为桥梁,本质是父子之间通信。

<!--
import { useState } from 'react';
import './index.css'
  // 组件1,组件2是app的子组件
  //组件1
function Component1({ onMsy}) {
  const msg = "this is 兄弟组件"

  return (
    <div>
      <button onClick={()=>onMsy(msg)}>兄弟组件</button>
    </div>
  )

}


//组件2
function Component2({onMsy2}) {
    console.log("兄弟组件通信",onMsy2);

}

//父组件
export default function App() {
  const [con, setCon] = useState('');
  const getMsg = (msg) => {
    console.log(msg);
    setCon(msg);
  }
  return (
    <div>
      <Component1 onMsy={getMsg}></Component1>
      <Component2 onMsy2={con}></Component2>
  </div>
  )
}

-->

跨组件通信--context

context 可以实现跨组件通信(可实现父与子之间通信)

父与子之间通信

<!--
import { useContext } from 'react';
import './index.css'
import { createContext } from 'react';

const ctx = createContext();
//组件1
function Component1() {
  const msgs= useContext(ctx);
  return (
    <div>
      <h1>{ msgs}</h1>
    </div>
  )

}

//组件2
function Component2() {
 const msgs= useContext(ctx);

    return (
      <div>
        <h2>{msgs}</h2>
      </div>
    )
}

//父组件
export default function App() {
  const getMsg ="这个是跨组件通信"
  return (
    <div>
      <ctx.Provider value={getMsg}>
        <Component1></Component1>
        <Component2></Component2>
      </ctx.Provider>

  </div>
  )
}

-->

三步骤

1.const ctx = createContext(); 创建一个上下文对象

2.顶层组件使用 ctx.Provider 组件传递数据

3.底层组件使用 useContext(ctx)接收数据

<!--
三代之间通信

import { useContext } from 'react';
import './index.css'
import { createContext } from 'react';

const ctx = createContext();

//组件1
function Component1() {
  return (
    <div>
      <Component2></Component2>
    </div>
  )

}


//组件2
function Component2() {
 const msgs= useContext(ctx);
    console.log(msgs);

}

//父组件
export default function App() {
  const getMsg ="这个是跨组件通信"
  return (
    <div>
      <ctx.Provider value={getMsg}>
      <Component1 ></Component1>
      </ctx.Provider>

  </div>
  )
}

-->

react 钩子 React Hook 函数 只能在顶层调用

useState 是一个 React Hook 函数,允许向组件添加一个状态变量,控制组件渲染效果

useState 的更新是异步的,这意味着它不会立即更新状态变量的值,而是将更新放在队列里在稍后时间执行

        const [index, setIndex] = useState(0);
        状态变量 设置函数 状态变量初始值
    
         修改变量方法:    setIndex(index+1)=>1

useState的使用

修改基本数据类型

<!-- const { useState } = require("react");

const Change = () => {
const [num,setNum] = useState(1);

  return (<div>
    <button onClick={()=> setNum(num+1)}>{num}</button>
  </div>
  )
}

export default function App(){

  return (<div>
   <Change></Change>
  </div>
  )
} -->

修改引用数据类型

使用扩展运算符展开原对象 创建一个新对象来替换整个对象 后面跟上修改的属性覆盖原对象的属性


<!-- const { useState } = require("react");

const Change = () => {
  const [Person, setPerson] = useState({
    name: "张三",
    age:20
  } );

  return (<div>
    <button onClick={() => setPerson({...Person,name:"王五"})}>修改名字{Person.name}</button>
    <button onClick={() => setPerson({...Person,age:24})}>修改年龄{Person.age}</button>

  </div>
  )
}

export default function App(){

  return (<div>
   <Change></Change>
  </div>
  )
} -->

嵌套对象的更新 一定要先对内部对象进行数据更改。更改后的对象为预对象,把它加到外部对象进行数据更新,最后通过 set 对整个对象更新。

<!--
const { useState } = require("react");



const Change = () => {
  const [person, setPerson] = useState({
    name: 'Niki de Saint Phalle',
    artwork: {
      title: 'Blue Nana',
      city: 'Hamburg',
      image: 'https://i.imgur.com/Sd1AgUOm.jpg',
    }

  });
  function handleClick() {
    //嵌套对象的数据更改,必须先对内部对象进行更新 并赋值给一个新对象。
    const newPer1 = {  ...person.artwork,
      title: "更新了内部对象"
    }
    //把更新好的内部对象 更新到外部对象上
    const newPer2 = {  ...person,artwork:
      newPer1
    }
    //更新对象
    setPerson(newPer2)

    console.log(person);
  }


  return (<div>
    <button onClick={handleClick}>嵌套对象更新</button>
    {/* <button onClick={handleClick2}>嵌套对象更新2</button> */}




  </div>
  )
}

export default function App(){

  return (<div>

    <Change ></Change>

  </div>
  )
} -->


添加数组


<!-- const { useState } = require("react");
let count = 1;

const Change = () => {
  const [person, setPerson] = useState([]);
  const [name, setName] = useState('');
  return (<div>
    <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
    <button onClick={() => setPerson([...person, { id: count++, name:name }])}>添加数组</button>
    <ul>
      {  person.map(per => (<li key={per.id}>{per.id}{  per.name}</li>))}
    </ul>

  </div>
  )
}

export default function App(){

  return (<div>

    <Change ></Change>

  </div>
  )
} -->

删除数组 (一一删除)


<!-- const { useState } = require("react");

const Change = () => {
  const [person, setPerson] = useState([
    { id: 0, name: 'Marta Colvin Andrade' },
    { id: 1, name: 'Lamidi Olonade Fakeye'},
    { id: 2, name: 'Louise Nevelson'},

  ]);

  return (<div>
   <ul>

      {person.map(per => (<li key={per.id}>{per.name}

        <button onClick={() => setPerson(person.filter(item => item.id!==per.id))}>删除数组</button>
                                                          新数组id和原数组id相同的删除
      </li>))}

    </ul>



  </div>
  )
}

export default function App(){

  return (<div>

    <Change ></Change>

  </div>
  )
} -->

插入数组

slice(0,1) 左开又闭合=>提取该返回内数据 slice(1)=>返回下标 1 之后的数据(2,3,4.....)

<!-- import { useState } from 'react';

let nextId = 3;
const initialArtists = [
  { id: 0, name: 'Marta Colvin Andrade' },
  { id: 1, name: 'Lamidi Olonade Fakeye'},
  { id: 2, name: 'Louise Nevelson'},
];

export default function List() {
  const [name, setName] = useState('');
  const [artists, setArtists] = useState(
    initialArtists
  );

  function handleClick() {
    const insertAt = 1;
    const nextArtists = [

          //提取该返回内数据 后面的数据都删除了
      ...artists.slice(0, insertAt),
          //数组添加
      { id: nextId++, name: name },
          //删除下标为1(包括1)之前的数据,返回剩余
      ...artists.slice(insertAt)

          //上述操作类似于一个数组的拼接 最后返回新数组给nextArtists
    ];
    setArtists(nextArtists);
    setName('');
  }

  return (
    <>
      <h1>Inspiring sculptors:</h1>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />

      <button onClick={handleClick}>
        Insert
      </button>

      <ul>
        {artists.map(artist => (
          <li key={artist.id}>{artist.name}</li>
        ))}
      </ul>
    </>
  );
} -->

反转数组 reslove

<!-- const { useState } = require("react");
const Change = () => {
  const [person, setPerson] = useState([
    { id: 0, name: 'Marta Colvin Andrade' },
    { id: 1, name: 'Lamidi Olonade Fakeye'},
    { id: 2, name: 'Louise Nevelson'},

  ]);
  function handleClick() {
    //先备份一个已经反转的数组,因为reverse() 和 sort() 方法正在改变原始数组,不能直接使用它们。
    const newList = [...person];
    //
    setPerson(newList.reverse());
  }
  return (<div>
     <button onClick={handleClick}>反转数组</button>
   <ul>
      {person.map(per => (<li key={per.id}>{per.name}

      </li>))}

    </ul>

  </div>
  )
}

export default function App(){

  return (<div>

    <Change ></Change>

  </div>
  )
} -->

useEffect 类似于 vue 的 mounted 浏览器重绘后触发

依赖项参数说明

没有依赖项 useEffect(()=>{}) 副作用:组件初始渲染执行+组件更新执行

有依赖项(空数组) useEffect(()=>{},[]) 副作用:组件初始渲染执行

传入特定依赖项 useEffect(()=>{},[count]) 副作用:组件初始渲染+依赖项变化时渲染

清除副作用 useEffect(()=> { return ()=>{} },[])

<!--

清除副作用


import {  useEffect, useState } from 'react';
import './index.css'

//子组件
function Component1() {
  useEffect(() => {
  const dsq=  setInterval(() => {
      console.log("这个是定时器....");
    })
    //清除定时器
    return () => {
      clearInterval(dsq);
    }
  },[])
  return (
    <div>
      <h1>这是子组件</h1>
    </div>
  )

}

//父组件
export default function App() {
  const [status,setStatus] = useState(true);
  return (
    <div>
      {status &&  < Component1/>}
      <button onClick={()=>setStatus(false)}>卸载组件</button>
  </div>
  )
}

 -->

useLayoutEffect 是 useEffect 的一个版本,它在浏览器重绘屏幕之前触发。

样式结构

常用外部导入 (行内样式 const style={color:red}对象结构 )

//index.css 文件

<!--
.foo{
color: red;
display: flex;
justify-content: center;
}
-->

//App.js 导入样式文件

<!--
import './index.css'
export default function App(){

  return (<div>

      <h2 className="foo">样式结构</h2>
  </div>
  )
} -->

综合案例 评论区

<!--

import { useEffect, useState } from 'react'
import './index.css'
export default function App() {
  const [num, setNum] = useState(0);
  const [list, setList] = useState([]);
  const [name, setName] = useState('');
  const [hover, setHover] = useState(null);   //控制鼠标滑动样式隐显
  const handleClick = () => {

    setList([
      ...list,
      {
        id: num+1, content: name
      }
    ])
    //索引加1
    setNum(num+1);
    setName('')
  }
  const handleMouseEnter = (id) => {
    setHover(id);
  }
  const handleMouseLeave = () => {
    setHover(null);
  }
  return (<div>
    <input
      value={name}
      onChange={e=>setName(e.target.value)}
    />
    <button onClick={handleClick}>添加</button>
    <div>
      <h3>评论区</h3>
    </div>
    <ul>
      {list.map(item => <div key={item.id}><span className={item.id===hover?'goo':'' } onMouseEnter={() => handleMouseEnter(item.id)} onMouseLeave={handleMouseLeave}>{item.content}</span>
        <button onClick={()=>setList(list.filter(it=>it.id!==item.id))}>删除</button>
      </div>


      )}
    </ul>
  </div>
  )
}

-->

React 获取 DOM 对象---useRef

<!--
      import { useEffect, useRef, useState } from 'react'
      import './index.css'
      export default function App() {

        const inputRef = useRef();//生成ref对象

        const handleClick = () => {

          //打印inputRef.current DOM详细数据

          console.dir(inputRef.current);
        }
        return (
          <div>

          {/* 将ref对象绑定到DOM上 */}
          <input type='text' ref={inputRef}/>

          <button onClick={handleClick}>添加</button>
        </div>
        )
      }
-->

自定义 hook(封装复用代码)

1.声明一个 use 开头的函数;

2.在函数体内封装可复用逻辑;

3.使用 return 把组件需要的回调出去(数组、对象形式);

4.在组件内使用函数

<!--

import { useState } from "react";
//自定义hook
function useTools() {
  const [val, setVal] = useState(false);
  const change = () => setVal(!val);
  //回调
  return {
    val,change
  }
}

const App = () => {
  const {val,change }=  useTools();

  return (
    <>
      {val && (
        <div>这个是自定义hook</div>
      )}
    <button onClick={change}>自定义</button>
    </>

  )
}
export default App;

 -->