美文网首页
使用memo优化遇到的问题

使用memo优化遇到的问题

作者: 云鹤道人张业斌 | 来源:发表于2021-08-12 17:11 被阅读0次

问题描述:下面是一个全选按钮组件Unlimited,可以传入一个点击事件,一个checked选中状态.

  1. 在组件中我使用memo避免在父组件中渲染时重复渲染
  2. memo有第二参数,返回true则不会渲染,想着只需要checked的状态来判断。默认浅比较prop,函数onChange都不一样都会重建导致渲染
export const Unlimited: FC<{ onChange: () => void; checked: boolean }> = memo(
  ({ onChange, checked }) => {
    return (
      <span
        className={styles.all}
        onClick={onChange}
        style={{ borderColor: checked ? '' : 'transparent' }}
      >
        不限
      </span>
    )
  },
  // (pre, next) => pre.checked === next.checked,
)

组件描述:使用场景

企业微信截图_16287553744598.png

1.页面首次加载,会有些参数从前页面跳转过来,回显这些条件。比如价格,酒店等级。这些条件又会以tag的形式显示在下面。

  1. 当点击上面组件:不限 将取消选中,且删除对应的tag
  2. 这里使用context 传递 组合好的newTages 数组,将会在价格,酒店组件中使用到,用于点击“不限”按钮,删除对应tag
tags组件用来回显选中的条件
const Tags = () => {
  const { tags, priceRange, star, confirmType } = useBarState()
  const dispatch = useDispatchBarState()
  const list = tags ?? []

  // 首次加载首页会有部分筛选条件回显
  useEffect(() => {
    const params: HotelParams = {
      priceRange,
      star,
      confirmType,
    }
    const newTages = Object.values(params).reduce((total, next) => {
      return total.concat(next ?? [])
    }, [])
    if (!newTages.length) return

    dispatch && dispatch({ tags: newTages })
  }, [])
.....省略代码
}

问题点: 这里可以发现,tags组件在选中组件下面,通过context 传递过去的数组 是在 价格,酒店组件初始化渲染之后。

这会导致第一步中的Unlimited全选组件onChange时间中使用的newTages 永远是undefined

来看价格组件代码:

export const PriceRange: FC = () => {
const { priceRange, tags } = useBarState()
  const newTages = tags ?? []
 console.log(newTages)   外部在tags组件dispatch后是可以拿到最新的newTages 
 console.log(123, newTages)    
  const handleAll = () => {
    console.log(234, newTages)     点击全选这里可拿不到最新的newTages 
    if (!(priceRange && priceRange.length)) return
    const tagsList= deleteAll(newTages, 'price')
 //   dispatch && dispatch({ priceRange: [], tags: tagsList})
  }

 return useMemo(() => {
    return <>
        <Unlimited
          onChange={handleAll}
          checked={!(priceRange && priceRange.length)}
        />
        <Radio.Group
          options={PRICE_RANGE}
          onChange={handleChange}
          value={defaultRadio}
        />
   </>
 }, [priceRange, tagsList,...])
}

看实际打印情况:首次渲染。外部123都拿到了最新的newTages


企业微信截图_16287566163795.png

点击不限按钮看看。哦吼,234 啥也没有


企业微信截图_16287566544145.png

解决: 问题就出在全选组件Unlimited的使用memo后第二参数上,删掉就好了。

由于只使用checked来控制组件的渲染,首次渲染的onChange函数拿到的newTages就是空,加上useCallBack包裹onChange,写上依赖newTags也没用

知道原因后,其实还有别的解决办法,由于初始化页面会组合前一个页面带来的参数。如果把Tags 组件中生成newTages的逻辑放到整个页面渲染之前也是可以行的

function HotelListPage() {
  const {
    location: { state },
  } = useHistory()
  const paramsState = useInitParams(true, state ?? {})

  //  在没有合并参数之前不渲染
  if (!paramsState.isHotel) {
    return null
  }
  return (
      <Main />
  )
}

把生成newTages的逻辑放到useInitParams中

// 初始化context
export const useInitParams = (isHotel: boolean = true, state?: any) => {
  const paramsState = useBarState()
  const dispatch = useDispatchBarState()

   const { priceRange, star, confirmType } = state ?? {}
   let tags = {}

   if (priceRange || star || confirmType) {
    tags = Object.values({ priceRange, star, confirmType }).reduce(
       (total, next) => {
        return total.concat(next ?? [])
      },
  /   [],
     )
   }

  useEffect(() => {
    dispatch &&
      dispatch({
        ...defaultValue,
        ...(isHotel ? hotelDefault : ticketDefault),
        ...(state ?? {}),
        // ...(tags && { tags }),
      })
  }, [])
  return paramsState
}

疑问: 组件大量使用Unlimited这样的memo第二参数到底好不好?

相关文章

网友评论

      本文标题:使用memo优化遇到的问题

      本文链接:https://www.haomeiwen.com/subject/duplbltx.html