React实践与小结

60 阅读4分钟

锚定(点击tab 对应内容置顶 )

changeTab(id) {
  this.currentIndex = id
  console.log('currentId', this.currentIndex)
  console.log('this.tabTop')
  let domObj
  let tabs = this.$refs.list_title
  let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
  this.tabTop = true
  console.log('this.$refs.report.$el', this.$refs.report.$el)
  switch (id) {
    case 1:
      domObj = this.$refs.report.$el
      break
    case 2:
      domObj = this.$refs.item_info
      break
    case 3:
      domObj = this.$refs.fitable.$el
      break
    default:
      break
  }
  scrollTop = domObj.getBoundingClientRect().top - tabs.getBoundingClientRect().height
  console.log('scrollTop', scrollTop)
  document.documentElement.scrollTop += scrollTop  //滚动条滚动的距离
  document.body.scrollTop += scrollTop
},

?.

做好条件判断 ?. 不是数组的话就会.map()白屏

const [cityList] = useState(() => {
  if (props?.cityList?.length) {
    return props?.cityList;
  }
  return []; //兜底策略 返回一个空值
});

封装组件注意的地方

  1. 简洁,注释写清楚
  2. 考虑多种情况

const [titleColor] = useState(() => {
  return props.titleColor || "White";   //状态数据默认值初始化,如果props有数据优先
});

//定义方法要写清楚参数包含的数据以及数据类型
function show(
  params = {
    data: {},
  }
) {
  xxx;
}


//注意兜底情况
{conf ? (
  <p></p>
) : null}

  • 弹框的城市item出现不能一行平铺 设置 box-sizing: border-box 怪异盒 解决点击不同的item时导致的盒子抖动
.item_city {
    width: 78px;
    box-sizing: border-box;
    padding:7px 0 6px 0;
    border: 1px solid rgba(233,193,162,1);
    border-radius: 18px;
    margin:0 15px 15px 0;
    &:nth-child(3n+3) {
      margin-right: 0;
    }
  }
  • 隐藏滚动条,且不影响滚动

使用 ::webkit-scrollbar 伪元素选择器,不过这个选择器只在 webkit 核心的浏览器中有效,例如 Chrome、新 Edge、Safari 等。::web-kit-scrollbar 可以直接选择滚动条元素,把它的 display 属性设置为 none 就可以隐藏滚动条了:

::-webkit-scrollbar { /* display: none; */ /* 或者 */ width: 0 !important; }
  • 设置滚动条并且隐藏滚动条
.city_item {
  box-sizing: border-box;
  height: 30vh;
  max-height: 448px;
  overflow: auto;    //重点
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  color: #E9C1A2;
  text-align: center;
  &::-webkit-scrollbar {
    display: none;         //隐藏滚动条样式
  }

}

react插槽

子组件中在插入位置写 {props.children}

父组件给子组件传入事件 任意事件名=父组件的方法名

受控与非受控

useSomething = (inputCount) => {
    const [ count, setCount ] = setState(inputCount);
    setCount(inputCount);
};

因为 useState 参数代表的是初始值,仅在 useSomething 初始时赋值给了 count state。后续 count 的状态将与 inputCount 无关。这种外部无法直接控制 state 的方式,我们称为非受控。 只有通过 setCount(inputCount)才可以改变count的值,执行setCount(),React会立即退出当前的渲染函数并用更新后的 state 重新执行 render 函数。

样式

1.CRA 支持 CSS Module ,并为提供了一种将 CSS 封装到组件范围内的模块的方法。这样,它就不会意外泄露到其他 React 组件的样式中。

import style from './list.module.css'
<h1 className="${style.font_style} ${style.content}" style={{ color: 'blue' }}></h1>
  1. styled components ,作为 React 的 CSS-in-JS 方式之一
import styled from 'styled-components';

const Head = styled.h1`
  color: blue;
`;

const Title = ({ title }) =>
  <Head>
    {title}
  </Head>

函数式组件

// React.createElement(Card, {
//     title: "XXX"
// });
const contentElement = <Card title="XXX" />;
ReactDOM.render(
    contentElement,
    document.getElementById('app')
);

React.js的hooks

以 “use” 作为开头的方法,可以避开使用 class式写法,在函数式组件中完成生命周期、状态管理、逻辑复用等几乎全部组件开发工作的能力。因此,hooks只能在函数组件中使用Eslint 通过判断一个方法是不是大坨峰命名来判断它是否是 React 函数。

为什么使用hooks?

  1. 状态复用

// 单个name的写法
const { name, setName } = useName();

// 多次使用的写法
const { name : firstName, setName : setFirstName } = useName();

const { name : secondName, setName : setSecondName } = useName();

  1. 告别this

vue中hooks的写法

<template>
  <div>
    {{ message }}
  </div>
</template>
<script setup>
import { computed, ref } from 'vue'
// 定义了一个 ref 对象
const name = ref('')
// 定义了一个依赖 name.value 的计算属性
const message = computed(() => {
  return `hello, my name is ${name.value}`
})
</script>

React中hooks的写法

import { useState, useEffect } from 'React'

export default () => {
  // 通过 useState 可以创建一个 状态属性 和一个改变状态数据的方法
  const [ name, setName ] = useState('')

  // 通过 useEffect 可以对状态数据改变之后需要的操作进行处理
  useEffect(() => {
    console.log(name)
  }, [ name ])

  // 通过 useMemo 能生成一个依赖 name 的变量 message
  const message = useMemo(() => {
    return `my name is ${name}`
  }, [name])

  return <div>{ message }</div>
}

useEffect

Effects 函数一旦执行,函数内的副作用已经发生,React 无法猜测到函数相比于上一次做了哪些变化。但我们可以给 useEffect 传入第二个参数,作为依赖数组 (deps),避免 Effects 不必要的重复调用。

useMemo

useMemo 通过一些变量计算得到新的值。通过把这些变量加入依赖 deps,当 deps的值都没有变化,就不会计算。useMemo 中传入的函数,将在 render 函数调用过程被同步调用。

useMemo的意义就是尽可能的使用缓存的值。

const data = useMemo(() => ({ a, b,d: 'xxx' }), [a, b]);

const memoComponentsA = useMemo(() => ( <ComponentsA {...props} /> ), [props]);

如果子组件使用了对象和数组作为 props,使用useMemo减少它们重新生成,避免子组件不必要的重复渲染,提升性能。

const data = { id };      //未优化
const data = useMemo(() => ({ id }), [id]);  //使用useMemo优化

return <Child data={data}>;

父组件渲染时,只要id不变,data的值也不会发生变化,子组件也不会 render。

一般组件内部对一个类似下面的content变量时,如果count改变使得整个组件重复的render,导致return的组件也要重新渲染,因此使用useMemo进行缓存,可减少元素渲染次数。

function Example(props) {
    const [count, setCount] = useState(0);
    const [foo] = useState("foo");

    const content = useMemo(() => (
        <div>
            <Item key={1} x={1} foo={foo} />
            <Item key={2} x={2} foo={foo} />
            <Item key={3} x={3} foo={foo} />
        </div>
    ), [foo]);

    return (
        <div>
            <p>{count}</p>
            <button onClick={() => setCount(count + 1)}>count</button>
            {content}
        </div>
    );
}